-
【C++】配列をサイズKのセグメントに分割し、すべてのセグメントにキーXが存在するか判定する方法
概要要素数 N の配列 arr1[]、検索対象のキー X、およびセグメントサイズ K が与えられたとき、「配列をサイズ K ごとの区間(セグメント)に区切った場合に、そのすべてのセグメントにキー X が含まれているか」を判定するのが本記事の課題です。入力例1arr1[] = { 4, 6, 3, 5, 10, 4, 2, 8, 4, 12, 13, 4}X = 4K = 3出力Yesこの配列は、サイズ 3 の重なり合わないセグメントが 4 つ、すなわち {4, 6, 3}、{5, 10, 4}、{2, 8, 4}、{12, 13, 4} に分けられます。いずれのセグメントにも 4 が含まれてい
-
【C++】N個のナイトがいる変形チェスボードで、キングが有効な手を指せるかどうかを判定する方法
概要通常のチェスと同じルールが適用される、無限に広がるチェスボードを考えます。ボード上にはN個のナイトが配置されており、それぞれの座標(-10^9 ≤ x, y ≤ 10^9)と、キングの座標が与えられます。このとき、キングがチェックメイトの状態にあるかどうかを判定するのが本記事の課題です。入力例1 {4, 3}出力:Yesキングはどの方向にも動くことができず、チェックメイトの状態です。入力例2 {3, 4}出力:Noキングは有効な手を指すことができます。解法のアプローチチェスの駒の中でも、ナイトの動きは特に独特です。ナイトは「横に2マス・縦に1マス」、あるいは「縦に2マス・横に1マス」移動し
-
C++で45度の直線により平面を重みの合計が等しい2つの領域に分割できるか判定する方法
問題概要 2次元平面上に n 個の異なる点 (Xi, Yi) が与えられ、それぞれの点には重み Wi が設定されています。このとき、直線の両側に存在する点の重みの合計が等しくなるような45度の直線を引けるかどうかを判定してください。 たとえば、入力が {{-1,1,3},{-2,1,1},{1,-1,4}} の場合、出力は TRUE となります。 アプローチ:座標変換と累積和 傾き45度の直線は、一般に「x − y = c(cは任意の定数)」という式で表せます。そこで各点を u = x − y という1つの値に変換すると、問題は「数直線上に配置された重みを、ある位置で2つのグループに分け、そ
-
C++で数値がトロイ数(Trojan Number)かどうかを判定する方法
概念与えられた数 n がトロイ数(Trojan Number)であるかどうかを判定するのが本記事のテーマです。トロイ数とは、「強い数(Strong Number)」の性質を持ちながら、累乗数(perfect power)ではない数として定義されます。ある数 n が強い数であるとは、n のすべての素因数 p について、p2 もまた n の約数となっていることを意味します。言い換えれば、すべての素因数が少なくとも2回以上現れる数のことです。ここで重要なのは、すべてのトロイ数は必ず強い数ですが、その逆は成り立たないという点です。つまり、強い数すべてがトロイ数というわけではなく、ab(a、b はともに
-
C++で数値がアキレス数かどうかを判定する方法
アキレス数とは正の整数 n が与えられたとき、その n がアキレス数であるかどうかを判定するのが本記事の課題です。n がアキレス数であれば「YES」を、そうでなければ「NO」を出力します。数学におけるアキレス数とは、累乗数(パワフルナンバー)でありながら、完全べき乗数ではない数として定義されます。累乗数:ある数 N のすべての素因数 p について、p² もまた N を割り切るような数のことです。完全べき乗数:m^k(m ≥ 1、k ≥ 2)の形で表せる数のことです。アキレス数の最初の例は以下の通りです。72, 108, 200, 288, 392, 432, 500, 648, 675, 80
-
C++で数値が素数階乗素数(プリモリアル素数)かどうかを判定する方法
概念 正の整数 n が与えられたとき、n が「素数階乗素数(プリモリアル素数)」であるかどうかを判定するのが本記事の目的です。n が素数階乗素数であれば「YES」を、そうでなければ「NO」を出力します。 素数階乗素数とは:数学において、素数階乗素数とは pN# + 1 または pN# − 1 の形で表される素数のことです。ここで pN# は最初の N 個の素数の積(素数階乗、プリモリアル)を表します。 入力例と出力例 入力: n = 7 出力: YES n = 7 の場合、N = 2 のときの素数階乗は 2 × 3 = 6 であり、6 + 1 = 7 となるため、7 は pN + 1 の形の
-
【C++】バックトラッキングでグリッドの8つのマスに1〜8の数字を条件付きで配置する方法
この記事では、図の中にある8つの丸(マス)に「1」から「8」までの数字を、「数列上で隣り合う数字同士がグリッド上でも隣接しない」という条件を満たすように配置する問題を、C++で解く方法を解説します。問題の概要たとえば、入力として次のような3×4のグリッドが与えられたとします。「0」は使用しないマス、「-1」はまだ数字が置かれていない空きマスを表します。0-1-10-1-1-1-10-1-10この場合の出力は次のようになります。 3 5 7 1 8 2 4 6この結果では、たとえば「1」と「2」、「7」と「8」のように数列で連続する数字が、グリッド上で上下左右・斜めに隣り合わないように配置
-
C++で要素の合計がNで割り切れる空でない部分集合を見つける方法
問題の概要n個の整数からなる配列が与えられたとき、要素の合計がnで割り切れるような空でない部分集合(サブセット)を1つ見つけることを考えます。そのような部分集合が存在する場合は、そのサイズと、元の配列における該当要素のインデックスを出力します。例えば、入力が [3, 2, 7, 1, 9] の場合、出力は次のようになります。[2][1 2]これは「サイズ2の部分集合であり、元の配列の1番目と2番目の要素(3 + 2 = 5)を選ぶと、合計がN=5で割り切れる」ことを意味しています。アルゴリズムの考え方この問題は累積和の剰余に着目することで効率的に解けます。先頭から順に累積和を計算し、それをNで
-
【C++】整数配列の全要素とのXOR合計が最小になる整数Xを求める方法
問題の概要負でない整数からなる配列 Arr[] が与えられたとき、次の式で表される合計が最小になるような整数 X を求めるのがこの記事のテーマです。(Arr[0] XOR X) + (Arr[1] XOR X) + … + (Arr[n − 1] XOR X)入力例:Arr[] = {3, 4, 5, 6, 7}出力例:X = 7, Sum = 10解法のアプローチこの問題は、各数値を2進数のビット列として捉え、ビットごとに独立して判断する貪欲法で効率的に解くことができます。基本的な考え方は次のとおりです。配列内の最大値から、調べるべきビット長を求めます。各ビット位置 i について、「i 番目
-
C++で指定された頂点集合から到達可能なすべてのノードを検索する方法
無向グラフと頂点の集合が与えられたとき、その集合に含まれる各頂点から到達可能なすべてのノードを見つけることを考えます。 たとえば、次のようなグラフが入力として与えられた場合: 出力は [1,2,3] と [4,5] になります。これはグラフが2つの連結成分に分かれているためです。 解法のアプローチ この問題を解くためには、次の手順に従います。 nodes := グラフ内のノード数を取得する サイズが nodes+1 の訪問済み配列 visited を定義し、すべて 0 で初期化する 結果を格納するためのマップ m を定義する comp_sum := 0(連結成分のカウンタ) i := 0
-
C++で単語列が昇順ソートとみなせるアルファベット順を見つける方法
問題概要英小文字からなる単語の配列が与えられたとき、与えられた単語列全体が「昇順にソートされている」とみなせるようなアルファベットの順序(独自の辞書式順序)を1つ見つけます。そのような順序が存在する場合はそれを出力し、存在しない場合は Impossible を返します。例えば、入力が words = [efgh, wxyz] の場合、出力は zyxvutsrqponmlkjihgfewdcba となります。この順序に従えば、「efgh」は「wxyz」より前に来るため、単語列は正しくソートされていることになります。解き方のアプローチこの問題は、トポロジカルソート(Kahnのアルゴリズム)を使うこ
-
【C++】配列内のちょうど1つの要素を除くすべての要素の約数となる整数の求め方
概念 整数の配列が与えられたとき、配列内のちょうど1つの要素を除くすべての要素の約数となる整数を求めることが課題です。 なお、この問題ではすべての要素の最大公約数(GCD)は1ではないものとします。これは、条件を満たす整数が必ず存在することを保証するための前提条件です。 入力例1 arr[] = {8, 16, 4, 24} 出力例1 8 8 は 4 を除くすべての要素の約数です。 入力例2 arr[] = {50, 15, 40, 41} 出力例2 5 5 は 41 を除くすべての要素の約数です。 解法のアプローチ まず、プレフィックス配列 A を作成します。A の位置 i には「先
-
C++で2つの系列を結合したときの平均と分散を求める方法
概要サイズ b の系列 arr1[] と、サイズ a の系列 arr2[] という2つの異なるデータ列が与えられたとき、両方を1つにまとめた「結合系列」の平均と分散を求めるのが本記事の目的です。これは統計学において、複数のグループそれぞれの統計量から全体の統計量を導き出す際に用いられる基本的な手法です。入力例Arr1[] = { 24, 46, 35, 79, 13, 77, 35 }; Arr2[] = { 66, 68, 35, 24, 46 };出力Mean1: 44.1429 Mean2: 47.8 StandardDeviation1: 548.694 StandardDeviati
-
C++でc[i] = d*a[i] + b[i]となる配列Cのゼロの個数を最大化するdの求め方
概要 M個の整数からなる2つの配列 a[] と b[] が与えられたとします。ここで、i番目の要素が d × a[i] + b[i] で表される配列Cを考えます(dは任意の実数)。本記事では、配列Cに含まれるゼロの個数が最大になるようなdの値を求め、そのゼロの個数を出力する方法を解説します。 入力例 a[] = {15, 40, 45} b[] = {4, 5, 6} 出力例 Value of d is: -0.133333 The number of zeros in array C is: 1 d を -0.133333 に設定すると、配列Cには1つのゼロが現れます。これが実現可能な
-
C++で行列のすべての行に共通する重複しない要素を効率的に検索する方法
概要m × m の正方行列が与えられたとき、その行列のすべての行に共通して現れる重複しない要素をすべて求めるのがこの問題です。出力される要素の順序は問われません。入力例mat[][] = { {13, 2, 15, 4, 17}, {15, 3, 2, 4, 36}, {15, 2, 15, 4, 12}, {15, 26, 4, 3, 2}, {2, 19, 4, 22, 15} }出力例2 4 15この例では、5つの行すべてに「2」「4」「15」が含まれているため、これら3つの値が出力されます。解法アプローチ方法1: 三重ループによる総当たり3つのネストしたループを使い、1行目の各要素がそ
-
C++でビット配列を活用して配列内の重複要素を検出する方法
概要n個の数値からなる配列が与えられます(nは最大32,000)。この配列には重複した要素が含まれている可能性がありますが、nの値は事前には分かりません。ここでの課題は、利用可能なメモリがわずか4キロバイトという厳しい制約のもとで、配列内のすべての重複要素をどのように検出・表示するかというものです。入力例arr[] = {2, 6, 2, 11, 13, 11}出力例2 11 2と11は、与えられた配列内で複数回出現しています。入力例arr[] = {60, 50, 60}出力例60アプローチ4キロバイトのメモリがあるということは、最大で 8 × 4 × 210 ビット(約327,680ビット
-
【C++】単調増加数列における要素の位置を二分探索で検索する方法
概要 整数 l と、次の式で定義される単調増加数列が与えられた場面を考えます。 f(m) = am + bm[log2(m)] + cm³ ここで、a = 1, 2, 3, …、b = 1, 2, 3, …、c = 0, 1, 2, 3, … です。記号 [log2(m)] は「底を2とする対数を取り、小数点以下を切り捨てた値」を意味します。具体的には次のようになります。 m = 1 のとき → 値は 0 m = 2〜3 のとき → 値は 1 m = 4〜7 のとき → 値は 2 m = 8〜15 のとき → 値は 3 この問題の目的は、f(m) = l を満たす m を特定することです。
-
C++で素数Pの倍数となる等差数列の最初の項を求める方法
概要初項 A と公差 d からなる等差数列(AP)と、ある素数 P が与えられたとき、この等差数列の中で素数 P の倍数となる最初の項の位置(インデックス)を求めるのが本記事の目的です。入力A = 3, d = 4, P = 5出力3説明この等差数列の第4項が、素数 5 の倍数になっています。第1項 = 3第2項 = 3 + 4 = 7第3項 = 3 + 2×4 = 11第4項 = 3 + 3×4 = 1515 = 5 × 3 であるため、第4項(インデックス 3)が最初の P の倍数となります。解法の考え方N番目の項を AN とすると、次のように表せます。AN = A + (N−1)×dAN
-
【C++】合計がNに等しく積が最大となるNの4つの約数の求め方(Set-2)
概要 ある整数Nが与えられたとき、Nのすべての約数を調査し、以下の2つの条件を同時に満たす「4つの約数の組み合わせ」を見つけて、その積を出力するのが本記事の目的です。 4つの約数の合計がNと等しいこと 4つの約数の積が最大であること 条件を満たす4つの約数が存在しない場合は「Not possible(不可能)」と出力します。なお、積を最大化するという観点から、4つの約数がすべて同じ値であっても問題ありません。 入力例 N = 60 出力例 All the factors are -> 1 2 3 4 5 6 10 12 15 20 30 60 Product is ->
-
C++で合計がNに等しく積が最大となるNの4つの約数を求める方法
概要整数 N が与えられたとき、次の条件を満たす N の4つの約数を見つけ、それらの積を出力することを考えます。4つの約数の合計が N に等しいこと。4つの約数の積が最大であること。もし条件を満たす4つの約数が存在しない場合は「Not possible(不可能)」と出力します。なお、積を最大化するためには、4つの約数がすべて同じ値であっても構いません。入力例80出力例All the factors are -> 1 2 4 5 8 10 16 20 40 80 Product is -> 160000この例では、約数 20 を4回選択しています。したがって、20 + 20 + 20