ツバサの備忘録

主に備忘録代わりに精進記録を載せていくつもりです。

CODE FESTIVAL 2018 qual A C - 半分

問題
提出コード

解法

動的計画法で答えを求めていくことを考えていきます。
まずは特徴についてです。
この問題では、0がとても重要なものになっています。
数列に0が存在していた場合、0は何回2で割っても0になるので、この部分を利用して与えられたKの調整が可能になります。
また、A_{i} = 10^{18}であった場合でも、60回程度2で割ることで0になります。
ということで、いかなる数字も、たかだか60回の操作を行うことで0になるので、その部分を利用して回数の調整が行えます。
ということで、すでに数列に0が存在しているかどうか、が重要になっていることがわかります。
あとは、
dp[i][j][l] = i番目までの数字を合計j回操作したときの数列の組み合わせの個数(ただしl=0のときは数列に0が存在せず、1のときは存在する)
として、答えを求めたくなります。
が、このままだと、与えられるKは10^{9}までありうるので、このままだと一見間に合わないように見えます。
ですが、先ほども述べたように、A_{i}はたかだか60回割ることですべて0になってしまうので、N=50の場合でも、K=3000ほどあれば十分であることになります。
ということで、先ほどのdpを利用して答えを求めていくことにします。
答え自体は、
dp[n][k][0]+dp[n][j][1]となっています。右の項については、jで全探索をすることになります。
重複組み合わせO(nm^{2})の解法で間に合うので、そちらを利用します。
基本的には、lは0でも1でも同様の処理が行えます。
A_{i}を、2で割って行って0にするために必要な回数をx_{i}とします。
dp[i][j][l]=\Sigma_{m=0}^{min(j,x_i-1)}dp[i-1][j-m][l]
となります。
加えて、 j \geqq x_iであったときのみ、
dp[i][j][1]+=dp[i-1][j-x_i][l]
という操作が加わります。
あとは、この操作をもとにDPを繰り返していけば、答えが求まります。