ABC 129 F - Takahashi's Basics in Education and Learning
O(n)では無理だし、実はO(1)になるみたいな性質も思いつかないので、うまく式を立てて繰り返し二乗法っぽく計算するしかないという気持ちになる。
整数siの桁数はあまり変化しない(最大で18桁までしか増えない)ので、桁数が等しい部分列ごとに連結して余りを計算するのがいちばん良さそうと思った。
(si)の部分列も公差Bの等差数列になるが、初項は異なるので、とりあえず初項α、公差Bの数列s0′,s1′,...について考える。また、すべてのsi′がd桁の数であるとする。s0′,s1′,...,sk−1′を問題の通りに連結してできた数をf(k)とするとき、
f(k)=s0′⋅10(k−1)d+s1′⋅10(k−2)d+...+sk−2′⋅10d+sk−1′=α⋅10(k−1)d+(α+B)⋅10(k−2)d+...+α+(k−1)B
と書ける。fがダブリングで計算できるか試してみる:
f(k+1)=f(k)10d+α+kB
f(2k)=α⋅10(2k−1)d+(α+B)⋅10(2k−2)d+...+α+(2k−1)B=(α⋅10(2k−1)d+(α+B)⋅10(2k−2)d+...+(α+(k−1)B)⋅10kd)+((α+kB)⋅10(k−1)d+(α+(k+1)B)⋅10(k−2)d+...+α+(2k−1)B)=10kd(α⋅10(k−1)d+(α+B)10(k−2)d+...+α+(k−1)B)+α⋅10(k−1)d+(α+B)10(k−2)d+...+α+(k−1)B+kB(10(k−1)d+...+10d+1)=(10kd+1)f(k)+kB(10(k−1)d+...+10d+1)
やはりこれで計算できそうなのだが、最後の式が問題である。求めたいのはmodMの値だったが、10(k−1)d+...+10d+1=(10kd−1)/(10d−1)という普通の変形では、分母とMが互いに素でないケースを扱えない。
kirika_compさんの整数論テクニック集に等比数列の和をダブリングで求める方法が載っている。g(k)=10(k−1)d+...+10d+1とするとき、
g(0)=0
g(k+1)=1+10dg(k)
g(2k)=(1+10kd)g(k)
で求まる。f(2k)=(10kd+1)f(k)+kBg(k)だから、これでfを計算できる。
あとは、(si)の1, 2, …, 18桁の部分だけ抜き出して連結した数を上のように(modMで)計算し、それらをさらに連結すれば答えになる。
A mod B problemに似てはいるが、細部を詰めるのがずっと難しい。50分とかで解けるようになるのはだいぶ先の話に思える。
というか、A mod B problemでやったダブリングは実質的には等比数列の和を求める操作だったのだけど、そういう自覚がなかったな。少し理解が進んだということにしておく。
解説は行列で計算してるけど、行列が自然に思い浮かばなければ実装する意味もないので保留……
→ 単にf(k+1)=f(k)10d+α+kBを行列に直せばいいのか。
⎝⎛f(k+1)k+11⎠⎞=⎝⎛10d00B10α11⎠⎞⎝⎛f(k)k1⎠⎞
となる。通した。漸化式を見て行列で書けそうという発想にさえなれば、50分で解くのも現実的に思えてきた。