2019年6月10日月曜日

ABC 129 F - Takahashi's Basics in Education and Learning

ABC 129 F - Takahashi's Basics in Education and Learning

O(n){\mathcal O}(n)では無理だし、実はO(1){\mathcal O}(1)になるみたいな性質も思いつかないので、うまく式を立てて繰り返し二乗法っぽく計算するしかないという気持ちになる。

整数sis_iの桁数はあまり変化しない(最大で18桁までしか増えない)ので、桁数が等しい部分列ごとに連結して余りを計算するのがいちばん良さそうと思った。

(si)(s_i)の部分列も公差BBの等差数列になるが、初項は異なるので、とりあえず初項α\alpha、公差BBの数列s0,s1,...s'_0, s'_1, ...について考える。また、すべてのsis'_idd桁の数であるとする。s0,s1,...,sk1s'_0, s'_1, ..., s'_{k-1}を問題の通りに連結してできた数をf(k)f(k)とするとき、

f(k)=s010(k1)d+s110(k2)d+...+sk210d+sk1=α10(k1)d+(α+B)10(k2)d+...+α+(k1)B \begin{aligned} f(k) & = s'_0 \cdot 10^{(k-1)d} + s'_1 \cdot 10^{(k-2)d} + ... + s'_{k-2}\cdot 10^d+ s'_{k-1} \\ & = \alpha \cdot 10^{(k-1)d} + (\alpha + B) \cdot 10^{(k-2)d} + ... + \alpha + (k-1)B \end{aligned}

と書ける。ffがダブリングで計算できるか試してみる:

f(k+1)=f(k)10d+α+kBf(k+1) = f(k)10^d + \alpha + kB
f(2k)=α10(2k1)d+(α+B)10(2k2)d+...+α+(2k1)B=(α10(2k1)d+(α+B)10(2k2)d+...+(α+(k1)B)10kd)+((α+kB)10(k1)d+(α+(k+1)B)10(k2)d+...+α+(2k1)B)=10kd(α10(k1)d+(α+B)10(k2)d+...+α+(k1)B)+α10(k1)d+(α+B)10(k2)d+...+α+(k1)B+kB(10(k1)d+...+10d+1)=(10kd+1)f(k)+kB(10(k1)d+...+10d+1) \begin{aligned} f(2k) & = \alpha \cdot 10^{(2k-1)d} + (\alpha + B) \cdot 10^{(2k-2)d} + ... + \alpha + (2k-1)B \\ & = \bigl( \alpha \cdot 10^{(2k-1)d} + (\alpha + B) \cdot 10^{(2k-2)d} + ... + (\alpha + (k-1)B)\cdot 10^{kd} \bigr) \\ & \qquad + \bigl( (\alpha + kB) \cdot 10^{(k-1)d} + (\alpha + (k+1)B) \cdot 10^{(k-2)d} + ... + \alpha + (2k-1)B \bigr) \\ & = 10^{kd} \bigl( \alpha \cdot 10^{(k-1)d} + (\alpha + B)10^{(k-2)d} + ... + \alpha + (k-1)B \bigr) \\ & \qquad +\alpha \cdot 10^{(k-1)d} + (\alpha + B)10^{(k-2)d} + ... + \alpha + (k-1)B\\ & \qquad +kB(10^{(k-1)d} + ... + 10^d + 1) \\ & = (10^{kd} + 1)f(k) + kB(10^{(k-1)d} + ... + 10^d + 1) \end{aligned}

やはりこれで計算できそうなのだが、最後の式が問題である。求めたいのはmod  M\mod Mの値だったが、10(k1)d+...+10d+1=(10kd1)/(10d1)10^{(k-1)d} + ... + 10^d + 1 = (10^{kd}-1)/(10^d-1)という普通の変形では、分母とMMが互いに素でないケースを扱えない。

kirika_compさんの整数論テクニック集に等比数列の和をダブリングで求める方法が載っている。g(k)=10(k1)d+...+10d+1g(k) = 10^{(k-1)d} + ... + 10^d + 1とするとき、

g(0)=0g(0) = 0
g(k+1)=1+10dg(k)g(k+1) = 1+ 10^d g(k)
g(2k)=(1+10kd)g(k)g(2k) = (1+10^{kd})g(k)

で求まる。f(2k)=(10kd+1)f(k)+kBg(k)f(2k) = (10^{kd}+1)f(k) +kBg(k)だから、これでffを計算できる。

あとは、(si)(s_i)の1, 2, …, 18桁の部分だけ抜き出して連結した数を上のように(mod  M\mod Mで)計算し、それらをさらに連結すれば答えになる。


A mod B problemに似てはいるが、細部を詰めるのがずっと難しい。50分とかで解けるようになるのはだいぶ先の話に思える。

というか、A mod B problemでやったダブリングは実質的には等比数列の和を求める操作だったのだけど、そういう自覚がなかったな。少し理解が進んだということにしておく。


解説は行列で計算してるけど、行列が自然に思い浮かばなければ実装する意味もないので保留……

→ 単にf(k+1)=f(k)10d+α+kBf(k+1) = f(k)10^d + \alpha + kBを行列に直せばいいのか。

(f(k+1)k+11)=(10dBα011001)(f(k)k1) \left( \begin{array}{c} f(k+1) \\ k+1 \\ 1 \end{array} \right) = \left( \begin{array}{ccc} 10^d & B & \alpha \\ 0 & 1 & 1 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{c} f(k) \\ k \\ 1 \end{array} \right)

となる。通した。漸化式を見て行列で書けそうという発想にさえなれば、50分で解くのも現実的に思えてきた。