-
木構造における部分木のDFSクエリをC++で効率的に処理する方法
この問題では、二分木が与えられ、特定のノードからDFS(深さ優先探索)を実行することが求められます。その際、与えられたノードを根(ルート)とみなして探索を行います。下の木構造では、ノードFからDFSを実行する場合を例に考えてみましょう。本チュートリアルでは、時間計算量を大幅に削減できる工夫された手法を適用することで、より大きな入力サイズでもコードを高速に実行できるようにします。アプローチこの手法では、クエリごとにすべてのノードからDFSをやり直す素朴な方法は採用しません。その方法では制約が大きい場合にTLE(実行時間超過)が発生する可能性が高いためです。代わりに、事前計算を活用した効率的な手法
-
【C++】累積和で解く!指定範囲内の偶数・奇数の出現確率を求めるクエリ処理
本記事では、指定された範囲に含まれる数値の偶奇(偶数か奇数か)の確率を求める問題を取り上げます。各クエリに対して、確率を p / q の形式で出力することが求められます。入力 : N = 5, arr[] = { 6, 5, 2, 1, 7 } query 1: 0 2 2 query 2: 1 2 5 query 3: 0 1 4 出力 : 0 3 4 1 2この問題では、「そのインデックスまでに出現した偶数の個数」と「奇数の個数」をそれぞれ記録した2つの配列を事前に構築しておきます。こうすることで問題が大幅に単純化され、各クエリに対しては範囲内の該当個数と要素総数から確率を計算して出力す
-
C++で文字列の部分文字列の総数を求める方法を解説
この記事では、与えられた文字列から作成できる空でない部分文字列の個数を求める方法について解説します。入力 : string = "moon" 出力 : 10 説明 : 部分文字列は m、o、o、n、mo、oo、on、moo、oon、moon の 10 個です。 入力 : string = "yellow" 出力 : 21解法のアプローチ文字列の長さを n とします。上の例からも分かるように、考えられるすべての部分文字列の個数を求めるには、長さ n、(n-1)、(n-2)、(n-3)、……2、1 の部分文字列の個数を順に加算していく必要があります。部分文
-
C++で一方の文字列の部分文字列がもう一方の文字列にいくつ含まれるかを調べる方法
この記事では、2つの文字列が与えられたとき、1つ目の文字列の部分文字列のうち、2つ目の文字列内に存在するものがいくつあるかを求める方法を解説します。なお、同じ部分文字列が複数回出現する場合は、その回数もカウント対象となります。具体例入力 : string1 = fogl string2 = google 出力 : 6 説明 : string2 内に存在する string1 の部分文字列は [ o, g, l, og, gl, ogl ] の6個です。 入力 : string1 = ajva string2 = java 出力 : 5 説明 : str
-
C++で解く!Nの階乗の16進数表現における末尾のゼロの個数の求め方
この記事では、与えられた整数Nの階乗(N!)を16進数で表したとき、末尾に何個のゼロが連続するかを求める問題について詳しく解説します。 入力 : N = 7 出力 : 1 説明 : fact(7) = 5040(10進数)で、16進数では13B0となり、末尾のゼロは1個です。 入力 : N = 11 出力 : 2 説明 : fact(11) = 39916800(10進数)で、16進数では2611500となり、末尾のゼロは2個です。 10進数から16進数への変換のおさらい まず、任意の10進数を別の基数へ変換する手順をおさらいしましょう。ここでは、(5040)10 を16進数に変換する例を
-
C++で解く!Nの階乗のB進表現における末尾ゼロの個数の求め方
はじめにこの記事では、与えられた数Nの階乗(N!)を基数Bで表したとき、末尾にいくつのゼロが連続するかを求める問題について詳しく解説します。問題の例入力 : N = 7、基数 = 2 出力 : 4 説明 : fact(7) = 5040(10進数)であり、2進数では「1001110110000」となるため、末尾にゼロが4個並びます。 入力 : N = 11、基数 = 5 出力 : 2 説明 : fact(11) = 39916800(10進数)であり、5進数では「40204314200」となるため、末尾にゼロが2個並びます。基数変換のおさらいまず、10進数から他の基数へ数値を変換する手順を確
-
C++でN回の操作後に存在する正三角形の数を求める方法
この記事では、色付きの三角形を描き、その中に存在する正三角形の数を求める方法を解説します。まず無色の三角形を用意し、それを4つの同じ面積を持つ小さな正三角形に分割します。この操作をn回繰り返し、最終的な図形の中にいくつの正三角形が存在するかを求めます。解決策へのアプローチこの問題を解くには、主に2つのアプローチがあります。総当たり(ブルートフォース)アプローチ観察すると、各ステップごとに三角形の数は「3 × 前回の数 + 2」という規則で増加していくことがわかります。したがって、n回ループを回すことで三角形の数を順次計算できます。コード例#include <iostream> us
-
C++で3本の直線上の点集合から形成できる三角形の個数を求める方法
問題概要3本の直線上にそれぞれ複数の点が配置されており、これらの点の中から3点を選んで三角形を作るとき、全部でいくつの三角形が作れるかを求めるのが本記事のテーマです。まずは具体例を見てみましょう。入力:m = 3, n = 4, k = 5出力:205入力:m = 2, n = 2, k = 1出力:10この問題は、組み合わせ(コンビネーション)の概念を活用することで、専用の数式を導出し、効率的に解くことが可能です。解法へのアプローチ本アプローチでは、組み合わせ論を適用して数式を導きます。この数式を用いることで、答えを直接計算できます。考え方のポイント3点が三角形を成すための条件は「その3点が
-
C++で配列内の一意なペア(ユニークペア)の数を求める方法をわかりやすく解説
C++で配列内に存在する一意なペア(ユニークペア)の数を求めるには、適切な考え方と実装方法を理解しておく必要があります。一意なペアの数を数えるとは、与えられた配列から作成できるすべてのペアの中で、重複しないペアだけをカウントすることを意味します。例えば、次のようなケースが挙げられます。入力 : array[ ] = { 5, 5, 9 } 出力 : 4 説明 : 一意なペアは (5, 5)、(5, 9)、(9, 5)、(9, 9) の4つです。 入力 : array[ ] = { 5, 4, 3, 2, 2 } 出力 : 16解決のためのアプローチこの問題を解くには、主に2つのアプローチがあ
-
C++でバイナリ文字列の「1」から始まる一意な順列の数を求める方法
この記事では、0と1で構成される文字列が与えられたとき、「1」で始まる順列の総数を求める問題を解説します。答えは非常に大きな数になる可能性があるため、1000000007で割った余り(mod)を出力します。 入力 : str = 10101001001 出力 : 210 入力 : str = 101110011 出力 : 56 本記事では、組み合わせ論(コンビネーション)の知識を応用し、この問題を解くための数式を導き出すことで解決していきます。 解法のアプローチ まず、文字列に含まれる「0」と「1」の個数をそれぞれ数えます。ここで、文字列内の1の個数を n、0の個数を m、与えられた文字列
-
C++で解く!範囲内の最大奇数約数のXORを求めるクエリ処理
N個の整数からなる配列と、範囲を指定するQ個のクエリが与えられます。各クエリに対して、指定された範囲内に含まれる各数値の「最大奇数約数」のXOR(排他的論理和)を返す必要があります。最大奇数約数とは、ある数Nを割り切る最大の奇数のことです。例えば、6の最大奇数約数は3です。入力: nums[ ] = { 3, 6, 7, 10 }, query[ ] = { { 0, 2 }, { 1, 3 } } 出力: query1: 7 query2: 1 説明: nums配列の各要素の最大奇数約数は { 3, 3, 7, 5 } です。 クエリ1ではインデックス0、1、2のXORである「7」を、クエ
-
C++で解く「すべての部分配列のXORのXOR」クエリ問題
本記事では、指定された範囲に含まれるすべての部分配列のXORを計算して出力する方法を解説します。問題の概要まず、具体的な例を見てみましょう。入力 : arr[] = { 4, 1, 2, 3, 5 }, Q = 3 クエリ q1 = { 1, 2 } q2 = { 2, 4 } q3 = { 1, 4 } 出力 : 0 2 0たとえばクエリ2(範囲 2〜4)の場合、対象となる部分配列は以下の通りです。{1}, {2}, {3}, {1, 2}, {2, 3}, {1, 2, 3}ここで各要素の出現回数を数えると、次のようになります。1 は 3 回出現2 は 4 回出現3 は 3 回出現XO
-
【C++入門】クエリで指定されたインデックスの左側にある0と1の個数を効率的に求める方法
本記事では、与えられた配列に対するクエリ処理の問題を解説します。各クエリで指定されたインデックスについて、そのインデックスより左側(手前)に存在する「0」の個数と「1」の個数を求めるのが目的です。問題の例入力: arr[ ] = { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0}, queries[ ] = { 2, 4, 1, 0, 5 } 出力: query 1: zeros = 1, ones = 1 query 2: zeros = 1, ones = 3 query 3: zeros = 1, ones = 0 query 4: zeros = 0, ones = 0 q
-
C++で解説:範囲合計クエリと平方根による範囲更新をBITで高速化する方法
配列と複数のクエリが与えられます。クエリには次の2種類があります。 update[ L, R ]:L番目からR番目までの各要素を、その平方根の値に更新する query[ L, R ]:L番目からR番目までの要素の合計を求める ここでは、1始まりのインデックスを持つ配列を想定します。以下に入力例と出力例を示します。 入力: nums[ ] = { 0, 9, 4, 1, 5, 2, 3 }, Query[ ] = { {1, 1, 3}, {2, 1, 2}, {1, 2, 5}, { 1, 4, 5}} 出力: 14 10 7 1つ目のクエリの最初の要素が「1」なので、1〜3の範囲合計
-
スパーステーブルを用いたC++の範囲合計クエリ(Range Sum Query)の実装方法
スパーステーブル(Sparse Table)は、範囲クエリ(Range Query)の結果を高速に取得するために用いられるデータ構造です。ほとんどの範囲クエリに対してO(logN)の計算量で答えを返すことができ、さらに最大値クエリのように演算の性質が許す場合には、O(1)で結果を求めることさえ可能です。 本チュートリアルでは、スパーステーブルを活用した「範囲合計クエリ」の問題を取り上げます。配列が与えられたとき、指定された区間 [L, R] に含まれる全要素の合計を求めるのが目標です。以下に入力例と出力例を示します。 Input: arr[ ] = { 2, 4, 1, 5, 6, 3 }
-
C++で解く複数ジャンプが可能な迷路のネズミ問題(Rat in a Maze)
問題の概要n×n のグリッド状の迷路が与えられ、ネズミはグリッドの左上のマスからスタートします。ネズミは「下」または「右」にのみ移動でき、さらに移動先のマスが 0 以外の値を持つ場合にのみ進むことができます。この問題のバリエーションでは、ネズミは複数マスのジャンプが許されており、現在のマスからジャンプできる最大距離はそのマスに書かれた数値です。ネズミがグリッドの右下のマスに到達できるかどうかを判定するのが課題です。以下に入力と出力の例を示します。入力 :{{1, 1, 1, 1},{2, 0, 0, 2},{3, 1, 0, 0},{0, 0, 0, 1}}出力 :{{1, 1, 1, 1},
-
等差数列(A.P.)の和の比が与えられたとき、m項目とn項目の項の比を求めるC++プログラム
本記事では、等差数列(A.P.)における初めの m 項の和と初めの n 項の和の比が与えられたときに、m 項目の項と n 項目の項の比を求める問題について解説します。入力: m = 8, n = 4 出力: 2.142 入力: m = 3, n = 2 出力: 1.666 入力: m = 7, n = 3 出力: 2.6解法のアプローチm 項目と n 項目の項の比をプログラムで求めるには、まず数式を簡略化する必要があります。ここで、Sm を等差数列の初めの m 項の和、Sn を初めの n 項の和とします。a … 初項d … 公差問題の条件として、次の関係式が成り立ちます。Sm / Sn =
-
C++で文字列をソート順に並べ替え、数字の合計を末尾に追加する方法
問題の概要本記事では、アルファベットと数字が混在する文字列を扱う問題を解説します。具体的には、アルファベット部分を辞書順に並べ替え、さらに文字列内のすべての数字を合計した値を末尾に追加するという処理を行います。入力 : str = adv4fc3 出力 : acdfv7 説明: すべての文字が「acdfv」にソートされ、その後に整数4と3の合計「7」が続きます。 入力 : str = h2d7e3f 出力 : defh12 説明: すべての文字が「defh」にソートされ、その後に整数2、7、3の合計「12」が続きます。解決のためのアプローチこの問題では、2つのタスクを実行する必要があります。
-
C++でマップ(HashMap)を反復処理中にキーを指定してエントリを削除する方法
C++では、連想配列である std::map(いわゆるHashMapに相当)から、特定のキーを持つエントリを削除したい場面はよくあります。本チュートリアルでは、マップを走査(イテレーション)している最中に、キーを指定してエントリを削除する方法を詳しく解説します。 問題の例 入力: HashMap: { 1: “Tutorials”, 2: “Tutorials”, 3: “Point” }, key=1 出力: HashMap: { 2: “
-
【C++】反復処理中に値を条件としてHashMapからエントリを削除する方法
この記事では、C++でHashMap(std::map)を反復処理している最中に、値を条件としてエントリを削除する方法を解説します。 入力: HashMap: { 1: Mango, 2: Orange, 3: Banana, 4: Apple }, value = Banana 出力: HashMap: { 1: Mango, 2: Orange, 4: Apple } 説明: 値Bananaに一致する3番目のキーと値のペアが削除されます。 入力: HashMap: { 1: Yellow, 2: White, 3: Green }, value = White 出力: HashM