X, Y, Zを5つ並べる。XYとYXは含まない /「算数にチャレンジ!!」第1175問

問題概略

X, Y, Zの 3 種類の文字を並べて長さが5の文字列を作ります。
X と Y が隣同士に並ばないような文字列は全部で何通り作ることができるでしょうか。

たとえば XXXXX, XXZYZ は条件をみたしますが XZYYX は条件をみたしません。

http://www.sansu.org/used-html/index1175.html

解説の pdf も作りました。きれいなレイアウトで読みたい方はこちらをどうぞ。

drive.google.com

漸化式を立てる

 n 文字並べたとき最後が X, Y, Z のものが  x_n,  y_n,  z_n 個あるとします。漸化式は次のようになります。

\begin{array}{l} x_1=y_1=z_1=1\\
x_{n}=x_{n-1}+z_{n-1}\\
y_{n}=y_{n-1}+z_{n-1}\\
z_{n}=x_{n-1}+y_{n-1}+z_{n-1}\mbox{ ……(1)}
\end{array}

この漸化式を使って  x_5+y_5+z_5 を求めればそれが答えですが,もう少し扱いやすい形に直してから計算したいと思います。

 f_n=x_n+y_n+z_n とおいて  f_5 を求めます。

(1)の漸化式を辺ごとに足して  z_n=f_{n-1} などを使うと  f_n\} だけの式が作れます。

\begin{align*}
f_{n}&=x_n+y_n+z_n\\
&=2(x_{n-1}+y_{n-1}+z_{n-1})+z_{n-1}\\
&=2f_{n-1}+f_{n-2}\mbox{ ……(2)}
\end{align*}

 f_1=3,  f_2=7 もわかります。これを繰り返し使うと解けます。99 通りです。

 f_3=17,\, f_4=41,\, f_5=99

n が非常に大きかったら?

プログラムを組んで非常に大きい  n に対して解を高速に求める方法について書きます。

置換で書く

 n が非常に大きいとき(1)や(2)は時間がかかりすぎるだけでなく,言語によっては再帰の回数が多すぎてエラーになってしまうので再帰を使わずに書きます。

X と Y は対等なので  x_n=y_n は明らかで,(1)は  x_n,  z_n だけの式に直せます。

\begin{array}{l}
x_1=z_1=1\\
x_{n}=x_{n-1}+z_{n-1}\\
z_{n}=2x_{n-1}+z_{n-1}=2x_{n}-z_{n-1}
\end{array}

 x\to x+z,  z\to 2x-z の置換を繰り返して,最後に  f_n=2x_n+z_n を求めます。
競技プログラミングによくある「 10^9+7 で割った余り」を求める形で書いてみました。
 n=10^6 で約 1.4 秒でした。

   In[]:= AbsoluteTiming[
      x = 1; z = 1;
      mod = 10^9 + 7;
      Do[x = Mod[x + z, mod]; z = Mod[2 x - z, mod], {n, 10^6 - 1}];
      ans = Mod[2 x + z, mod]]
     
   Out[]= {1.37417, 400591637}

繰り返し二乗法を使う

(2)の漸化式を行列で書きます。

\begin{align*}
&\begin{pmatrix}f_n\\ f_{n-1}\end{pmatrix}
=\begin{pmatrix}2f_{n-1}+f_{n-2}\\ f_{n-1}\end{pmatrix}
=\begin{pmatrix}2&1\\1&0\end{pmatrix}
\begin{pmatrix}f_{n-1}\\f_{n-2}\end{pmatrix}\\
&\therefore \begin{pmatrix}f_n\\ f_{n-2}\end{pmatrix}
=\begin{pmatrix}2&1\\1&0\end{pmatrix}^{n-2}
\begin{pmatrix}f_{2}\\f_{1}\end{pmatrix}
=\begin{pmatrix}2&1\\1&0\end{pmatrix}^{n-2}
\begin{pmatrix}7\\3\end{pmatrix}
\end{align*}

 n-2 乗の計算に MatrixPowerMod を使うと,繰り返し二乗法で処理してくれます。
 n=10^6 の計算が約  \log_2 10^6 \approx 20 回で終わって約  1.0\times 10^{-4} 秒で答えが出ます。

   In[]:= AbsoluteTiming[
      m = {{2, 1}, {1, 0}};
      mod = 10^9 + 7;
      ans = First@Algebra`MatrixPowerMod[m, 10^6 - 2, mod] . {7, 3};
      ans = Mod[ans, mod]]
     
   Out[]= {0.0001012, 400591637}


variee.hatenablog.com