2019年7月4日木曜日

ARC 084 D - Small Multiple

ARC 084 D - Small Multiple

問題: 0,1,...,90, 1, ..., 9 のいずれかの整数からなる有限長の数列(di)i{0,1,...,m1}(d_i)_{i \in \{0, 1, ..., m-1\}}で、法KK

100d0+101d1+...+10m1dm1=010^0 \cdot d_0 + 10^1\cdot d_1 + ... + 10^{m-1} \cdot d_{m-1} = 0

を満たすようなものについて、数列の総和 d0+d1+...+dm1d_0+d_1+...+d_{m-1}の最小値を求めたい。

まず、各桁did_i0,1,...,,90, 1, ..., ,9の代わりに非負整数全体で考えてよい。というのも、ある桁が1010以上である場合、それより桁和が小さい数列で同じ数を与えるものが必ず存在する(例: 10013+101110^0 \cdot 13 + 10^1 \cdot 1 なら 1003+101210^0 \cdot 3 + 10^1 \cdot 2)ので最小値は変わらないからである。

さて、dp[l][x]dp[l][x]を次のように定める: 100,101,102,...10^0, 10^1, 10^2, ...から(重複を許して)ll個選んで足し合わせて整数xxを作ることが可能ならdp[l][x]=1dp[l][x]=1、そのような選び方が存在しないならdp[l][x]=0dp[l][x]=0。このとき、dp[l][0]=1dp[l][0]=1になるような最小のl>0l>0が答えである。

dpdpの漸化式を与える。ll個の和で作れる数は、l1l-1個の和で作れる数と100,101,102,...10^0, 10^1, 10^2, ...のいずれかの和で作られるので、

dp[l][x]=i=0x(dp[l1][xi]dp[1][i])dp[l][x] = \bigvee_{i=0}^{x} \bigl(dp[l-1][x-i] \wedge dp[1][i] \bigr)

と表すことができて、これは畳み込みの形になっている。ブール代数に特化した効率的な畳み込みアルゴリズムは見あたらなかったが、単純に(+,×)(+, \times)でFFTしたあと、11以上の数をすべて11に訂正すればよい。なお、実際に計算するにあたっては、1次元のdpdpに対してin-placeに更新できる。

入力の制約より、答えは9+9+9+9+9=459+9+9+9+9=45を超えないので、高々43回畳み込みすればよいことになる。オーダーで表すとO(Klog2K){\mathcal O}(K \log^2 K)


kyopro_friendsさんに教えていただいた解法だが、ちゃんと理解したと思えるのに時間がかかった。というか、ブール代数上の畳み込みが普通のFFTでできるというのがいまだに不思議だったりする。

https://mathoverflow.net/questions/10237/does-the-convolution-theorem-apply-to-weaker-algebraic-structures
convolution theoremでググったら見つかったトピック。おもしろそう(難しそう)。


dpdp

dp[x]:={1(xが10の累乗)+(それ以外)dp[x] := \begin{cases} 1 & \qquad (\text{$x$が10の累乗}) \\ +\infty &\qquad (\text{それ以外}) \end{cases}

と初期化して、畳み込み

dp[x]:=min0ix(dp[xi]+dp[i])dp[x] := \min_{0 \le i \le x} (dp[x-i] + dp[i])

を繰り返すのでもできそう? (min,+)(\min, +)の畳み込みはFFTほど効率的にはできないらしいけど、こう書き下すと最短経路問題であることはわかりやすくなる。つまり、100,101,102,...,10^0, 10^1, 10^2, ...,を足す操作を有向辺にしたとき、dp[x]dp[x]は最終的に頂点00から頂点xxへの最短経路長になるので、BFSでも求まる。ただ、これだと想定のオーダーに達してはいない。1 +1+1×10\times 10だけで十分というのを自然に導きたいけど……


  1. というか間に合っていない。計算量はO(K2){\mathcal O}(K^2)で、1010の位数が大きい場合が問題になる。間に合わない場合は(密グラフなので)どうせ3だろうと決め打てば一応通るけど…… ↩︎