-
C++で最初のN個の自然数の2乗の和がX以下となる最大のNを求める方法
概要整数 X が与えられたとき、最初の N 個の自然数の2乗の和が X を超えないような最大の N を求めるのが本記事の目的です。入力例と出力例例1X = 7出力:2N = 3 の場合、級数の和は 12 + 22 + 32 = 1 + 4 + 9 = 14 となり X を超えてしまうため、2 が N の最大値となります。例2X = 27出力:3N = 4 の場合、12 + 22 + 32 + 42 = 1 + 4 + 9 + 16 = 30 となり X を超えるため、3 が最大値となります。解法アプローチ単純な解法(線形探索)最もシンプルな方法は、1 から順にループを実行し、S(N) ≤ X
-
C++でNを1に減らすための最大操作回数を見つける方法
概念 2つの整数 P と Q(いずれも最大 106)が与えられ、そこから N = P!/Q! という数が構成されます。この課題の目標は、実行可能な限り多くの操作を繰り返して N を 1 まで減らすことです。ただし、1回の操作では「N がある数 X で割り切れる場合に、N を N/X で置き換える」ことしかできません。このとき実現できる操作回数の最大値を求めます。 入出力例 例 1 入力: A = 7, B = 4 出力: 4 説明: N は 210 となり、素因数は 2・3・5・7 の 4 個です。それぞれで順に割ることで、ちょうど 4 回の操作で 1 になります。 例 2 入力: A =
-
C++で配列から要素を削除して得られる最大ポイントを求める方法
概要N個の要素を持つ配列Aと、2つの整数l、rが与えられます。ここで、各要素は 1 ≤ ax ≤ 105 を満たし、1 ≤ l ≤ r ≤ N という条件が成り立ちます。配列内の任意の要素(axとします)を選んで削除すると、同時に ax+1、ax+2 … ax+R および ax-1、ax-2 … ax-L に等しいすべての要素も配列から取り除くことができます。この操作を行うたびに ax ポイントを獲得でき、目的は配列の全要素を削除し終えた時点での合計ポイントを最大化することです。入力例12 1 2 3 2 2 1l = 1, r = 1出力例18この例では、まず「2」を削除対象として選択します
-
C++で配列内の最大トリプレット合計を求める方法(i < j < k かつ a[i] < a[j] < a[k] の条件付き)
概要サイズ n の正整数からなる配列が与えられたとき、0 <= i < j < k < n かつ ai < aj < ak を満たすトリプレット(ai + aj + ak)の中で最大の合計値を求めるのが本記事の課題です。入力例a[] = 3 6 4 2 5 10出力例19説明考えられるすべてのトリプレットは以下の通りです。 3 4 5 => 合計 = 12 3 6 10 => 合計 = 19 3 4 10 => 合計 = 17 4 5 10 => 合計 = 19 2 5 10 => 合計 = 17 最大合計 = 19解法アプロー
-
C++でBSTの中央値をO(n)時間・O(1)空間で求める方法
基本概念 与えられた二分探索木(BST)に対して、その中央値を求めることが本記事の目的です。 中央値の定義はノード数によって異なります。 ・ノード数が奇数の場合:中央値 = (n+1)/2 番目のノードの値 ・ノード数が偶数の場合:中央値 = ((n/2 番目のノード + (n+1)/2 番目のノード) / 2 例1:ノード数が奇数のBST 7 / \ 4 9 / \ / \ 2
-
C++で複数スレッド間のメモリ競合を検出するアルゴリズム
RAMがブロック単位で構成されており、システム上では複数のプロセスが同時に動作している状況を想定します。各プロセスは次のような形式のアクセス情報を持っています。(スレッドT、メモリブロックM、時刻t、R/W)これは、スレッドTが時刻tにメモリブロックMへアクセスし、その操作が読み取り(R)または書き込み(W)のいずれかであったことを意味します。メモリ競合の判定条件メモリ競合が発生しているかどうかは、以下のルールで判断されます。同じメモリ位置に対する複数の読み取り操作は、競合の原因にはなりません。あるスレッドが時刻xにメモリ位置Mへアクセスしている場合、x−5からx+5の範囲内で書き込み操作が行
-
C++で配列の最小調整コストを求める方法
概念正の整数からなる配列が与えられたとき、隣接する要素同士の差が指定されたtarget以下になるように、配列内の各要素を置き換えることを考えます。このとき私たちの課題は、調整コスト(新しい値と元の値の差の総和)を最小化することです。つまり、Σ|A[i] − Anew[i]|(0 ≤ i ≤ n−1)を最小化する必要があります。ここで、nは配列A[]のサイズ、Anew[]は隣接要素間の差がtarget以下となるように調整した配列を表します。なお、配列のすべての要素は定数M=100より小さいものと仮定します。入力例arr = [56, 78, 53, 62, 40, 7, 26, 61, 50,
-
C++でフローネットワークの最小s-tカットを求める方法
最小s-tカットとは フローネットワークが与えられたとき、s-tカットとは、始点(ソース)ノード s と終点(シンク)ノード t が必ず異なる部分集合に振り分けられるような頂点の分割を指します。カットには、ソース側の集合からシンク側の集合へ向かう辺が含まれ、その容量はカット集合に含まれる各辺の容量の総和で表されます。 この記事では、与えられたネットワークの中から容量が最小となるs-tカット(最小カット)を見つけ、それを構成するすべての辺を出力する方法を解説します。 たとえば、次のようなネットワークが入力されたとします。 このときの出力は [(1,3), (4,3), (4,5)] となりま
-
C++で制約条件を満たしながら全ジョブを完了させる最短時間を求めるアルゴリズム
概要それぞれ所要時間の異なるジョブの配列が与えられ、k人の同一の作業者が利用可能であり、さらに作業者がジョブ1単位を完了するのにかかる時間も分かっているものとします。このとき、以下の制約条件下で全ジョブを完了するための最小時間を求めるのが本問題の目的です。制約条件制約1: 1人の作業者に割り当てられるのは「連続した」ジョブのみです。例えば、配列内の位置1と位置2のジョブは同じ作業者に割り当てられますが、それとは別に位置3だけを同じ作業者に割り当てることはできません。制約2: 複数の作業者が1つのジョブを分担することはできません。つまり、あるジョブを一人の作業者に部分的に、別の作業者にも部分的に
-
【C++】昇順ソート済みの連続数列から欠落している要素を二分探索で効率的に見つける方法
概要 互いに異なる n 個の整数が格納された配列 array[] が与えられます。要素は昇順に並んでいますが、そのうち1つだけが欠落しています。この記事では、その欠落要素を効率よく特定するアルゴリズムを、原理からサンプルコードまでわかりやすく解説します。 入出力例 例1:欠落要素がある場合 入力: array[] = {1, 2, 3, 4, 5, 6, 7, 9} 出力: 8 例2:負の数を含む場合 入力: array[] = {-4, -2, -1, 0, 1, 2} 出力: -3 例3:欠落要素がない場合 入力: array[] = {1, 2, 3, 4} 出力: -1 すべて
-
C++で二分木の同じ階層にある葉ノードの合計値の積を求める方法
概要 与えられた二分木(バイナリツリー)に対して、次の値を返すプログラムを考えます。 各階層(レベル)について、その階層に葉ノードが存在する場合は、すべての葉ノードのデータの合計を計算します。存在しない場合はその階層を無視します。 計算されたすべての階層ごとの合計値を掛け合わせ、その結果を返します。 入力例1 次の木のルート 3 / \ 8 6 \ &nbs
-
C++でビットごとのORがKに等しくなるN個の異なる整数を見つける方法
概要 2つの整数 N と K が与えられたとき、N 個の相異なる整数を選んでビットごとのOR(論理和)を計算した結果が、ちょうど K に等しくなるような組み合わせを見つけるのがこの問題の目的です。条件を満たす解が存在しない場合は -1 を出力します。 入力例と出力例 例1:解が存在する場合 入力: N = 4, K = 6 出力: 6 0 1 2 例2:解が存在しない場合 入力: N = 11, K = 6 出力: -1 この場合、条件を満たす組み合わせが存在しないため、解を求めることはできません。 解法のアプローチ 複数の数のビットごとのORが K になるとき、K で 0 になっているビッ
-
C++で文字列のn番目の辞書式順列を求める方法
概要 小文字のアルファベットのみで構成された長さmの文字列が与えられたとき、その文字列の順列を辞書順に並べた場合のn番目の順列を求めるのがこの問題の目的です。 入力例 str[] = "pqr", n = 3 出力例 Result = "qpr" 解説 「pqr」のすべての順列を辞書順に並べると、pqr、prq、qpr、qrp、rpq、rqp の6通りになります。3番目は「qpr」です。 入力例 str[] = "xyx", n = 2 出力例 Result = "xyx" 解説 重複した文字を含む場合、「xyx
-
C++で漸化式のn番目の項を求めるアルゴリズム
概要数列 bn が次の漸化式で定義されているとします。b1 = 1bn+1 / bn = 2nこのとき、与えられた n に対して log2(bn) の値を求めるのが本記事の目的です。入出力例入力16出力115説明: 後述の通り log2(bn) = n(n − 1) / 2 となるため、(6 × (6 − 1)) / 2 = 15 が出力されます。入力2200出力219900解法の考え方(一般項の導出)まず、漸化式の関係を n の降順に書き並べます。bn+1 / bn = 2nbn / bn−1 = 2n−1…b2 / b1 = 21これらの式をすべて辺々掛け合わせると、左辺の分子と分母が打ち
-
C++で木を分割した際の2つの部分木のビット単位ORが等しくなる辺の数を求める方法
概要m個のノードからなる木があり、それぞれのノードには数値が割り当てられているとします。この木の任意の辺を切断すると、2つの新しい木が生成されます。ここでの課題は、ある辺を切断した後に構成される2つの木それぞれのノード値のビット単位OR(Bitwise OR)が等しくなるような辺の数を数えることです。なお、各ノードの値は10^6以下であることが保証されています。入力例values[]={1, 3, 1, 3} 1 / | \ 2 3 4出力例2この例では、ノード1とノード2をつなぐ辺を切断すると、結果として得られる2つの木のビット単位ORはどちらも3になります。同様に、ノ
-
C++で全ペアのGCDから元の数値を復元する方法
概要 ある配列 array[] には、別の配列に含まれる要素同士の「すべての可能なペア」に対して計算されたGCD(最大公約数)の値が格納されています。本記事では、このGCD配列をもとに、計算に使われた元の数値を復元するアルゴリズムをC++で解説します。 入力例 array[] = {6, 1, 1, 13} 出力例 13 6 gcd(13, 13) = 13 gcd(13, 6) = 1 gcd(6, 13) = 1 gcd(6, 6) = 6 入力例(長いケース) arr[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6
-
C++で補助領域なしにソート済み単方向リンクリストから指定した合計になるペアを検索する方法
問題の概要 ソート済みの単方向リンクリストと値 x が与えられたとします。このとき、ノードのデータの合計が x と等しくなるペアをすべて見つける必要があります。ただし、追加の補助領域(余分なメモリ)を使用することはできず、期待される時間計算量は O(n) です。 例として、入力が 4→7→8→9→10→11→12 で、x = 19 の場合、出力は (7, 12)、(8, 11)、(9, 10) となります。 解決のアプローチ:XORリンクリストの活用 配列であれば「両端から中央へ向かう2ポインタ法」で簡単に解けますが、単方向リンクリストは逆方向へ移動できません。そこで、各ノードの next ポ
-
C++でバイナリ行列内の最大ビット差を持つ行のペアを見つける方法
バイナリ行列(0と1のみで構成される行列)が与えられたとき、その中からビット差が最大となる2つの行のペアを見つける問題を考えてみましょう。例えば、次のような行列が入力された場合を想定します。{1, 1, 1, 1}, {1, 0, 1, 1}, {0, 1, 0, 0}, {1, 0, 0, 0}この場合、出力は (2, 3) となります。なぜなら、2行目と3行目のビット差は4であり、これがすべての行の組み合わせの中で最大だからです。解決策:Trie(トライ木)を使った効率的なアプローチこの問題は、各行をビット列として扱い、Trie(トライ木)というデータ構造を利用することで効率的に解くことが
-
C++でソート済み双方向リンクリストから積が指定値と一致するペアを検索する方法
概要 正の相異なる要素で構成されたソート済みの双方向リンクリスト(Doubly Linked List)が与えられたとき、ノード同士の積が指定した値 x と等しくなるペアをすべて見つけるのが本記事の課題です。ポイントは、余分なメモリ領域を使用せずに解くことです。 入力例と出力例 例1 List = 1 <=> 2 <=> 4 <=> 5 <=> 6 <=> 8 <=> 9 x = 8 出力: (1, 8), (2, 4) 例2 List1 = 1 <=> 2 <=> 3 <=> 4 &
-
【C++解説】配列内で隣接しない要素同士の最大合計を求める方法
この記事では、配列 arr[] が与えられたときに、「選んだ2つの要素が元の配列内で隣り合わない」という条件を満たす最大合計を求めるプログラムをC++で実装する方法を解説します。 問題の概要 配列の中からいくつかの要素を選び、その合計を最大化することを考えます。ただし、選んだ要素どうしが元の配列内で隣接してはいけないという制約が付きます。この条件のもとで達成できる最大の合計値を求めるのが本問題です。 具体例を見てみましょう。 入力 arr[] = {5, 1, 3, 7, 9, 2, 5} 出力 22 解説 インデックス0から1つおきに要素を選んだ場合 : 5 + 3 + 9 + 5 = 22