C++で長さLの文字列における魔法のペア(マジカルペア)の数を求める方法
2つの文字列 str1 と str2 が与えられたとき、長さLの「魔法のペア」の数を求める問題を考えてみましょう。すべてのインデックス i について str1[i] < str2[i] が成り立つとき、この2つの文字列は魔法のペアであると定義されます。ペアの総数は非常に大きな値になる可能性があるため、答えは 109 を法とした剰余として返します。なお、文字列には小文字の英字のみが含まれるものとします。
考え方
この問題のアプローチはシンプルです。まず長さ L = 1 の場合を考えてみます。インデックス i = 1 の位置にある str1 の文字が 'a' であるとき、対応する str2 の文字は 'b' から 'z' までの25通りから選ぶことができます。次に str1 の文字が 'b' であれば、str2 は 'c' 以降の24通りとなり、以下同様に選択肢が1つずつ減っていきます。
したがって、1文字あたりの組み合わせの総数は次のように計算できます。
25 + 24 + … + 1 = 325
長さ L = 2 の場合は、各位置の選択が互いに独立しているため、組み合わせの総数は 3252 となります。一般化すると、長さ L のときの答えは 325L です。この値は指数関数的に増大するため、実際の計算では 109 で割った余りを求めます。
べき乗の計算には繰り返し二乗法(バイナリ累乗法)を用いることで、時間計算量 O(log L) で効率的に結果を得られます。
実装例
#include<iostream>
#include<cmath>
using namespace std;
int power(int a, unsigned int b, int mod) {
int res = 1;
a = a % mod;
while (b > 0) {
if (b & 1)
res = (res * a) % mod;
b = b >> 1;
a = (a * a) % mod;
}
return res;
}
int main() {
int L = 2, P = pow(10, 9);
int res = power(325, L, P);
cout << "Combinations: " << res << endl;
}
出力
Combinations: 105625
まとめ
長さLの魔法のペアの総数は、1文字あたり325通りの組み合わせを基に 325L という式で表せることが分かりました。繰り返し二乗法とモジュロ演算を組み合わせることで、L が非常に大きい場合でもオーバーフローを防ぎながら高速に答えを計算することができます。
-
C++でソート済みバイナリ配列に含まれる0の個数を数える方法
この問題では、0と1のみで構成されるバイナリ配列 bin[] が与えられ、その中に含まれる0の個数を求めることが課題となります。 配列はソート済みであり、すべての1が先頭に、すべての0が後ろにまとめて配置されています。つまり、最初の0が現れる位置が分かれば、残りの要素はすべて0であるため、簡単に個数を計算できます。 問題の例 入力: arr[] = {1, 1, 1, 0, 0, 0, 0} 出力: 4 この例では、配列の後半に0が4つ連続しているため、答えは「4」となります。 解決アプローチ この問題を解く鍵となるのは「配列がソート済みである」という性質です。配列内で最初に0が出現するイン
-
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 の部分文字列の個数を順に加算していく必要があります。部分文