UVa 12410 Disable the Wand
問題
start以上end以下で以下の条件を満たす数の総和を求めよ。
- 2進法で書いたときに1の数がmaxone個以下
- 2進法で書いたときにIdeal Numberと違う桁がk個以下
制約条件
全ての入力は10^9以下の正の整数
方針
典型的な桁DP.
ある数n以下で条件を満たす数の総和を求められればいい。
dp[i][one][diff][mod][s]を、
i桁目まで見たときの、1の数がone個、ideal numberとの違いをdiff個、
21で割った余りがmodであり、
s = 1ならn未満になっていて、
s = 0ならそうでないときの総和。
これを更新していけばいい。
今までに至る場合の数も記憶しておいて、その分だけ次の桁を足す。
ソースコード
ll s, t, one, ideal, diff; int lim[40], id[40]; ll dp[40][40][40][21][2]; ll way[40][40][40][21][2]; ll solve(ll l){ rep(i, 32) lim[i] = l % 2, l /= 2; reverse(lim, lim + 32); memset(dp, 0, sizeof(dp)); memset(way, 0, sizeof(way)); way[0][0][0][0][0] = 1; rep(i, 32) rep(j, one + 1) rep(k, diff + 1) rep(l, 21) rep(m, 2){ if(way[i][j][k][l][m]) rep(nxt, 2){ if(!m && nxt > lim[i]) continue; int nj = j + nxt; int nk = k + (id[i] != nxt); int nl = (l * 2 + nxt) % 21; int nm = m || nxt < lim[i]; if(nj > one || nk > diff) continue; dp[i + 1][nj][nk][nl][nm] += dp[i][j][k][l][m] * 2 + nxt * way[i][j][k][l][m]; way[i + 1][nj][nk][nl][nm] += way[i][j][k][l][m]; } } ll ans = 0; rep(i, one + 1) rep(j, diff + 1) rep(k, 21) rep(l, 2){ if(k % 3 == 0 && k % 7) ans += dp[32][i][j][k][l]; } return ans; } int main() { int CS; cin >> CS; rep(cs, CS){ cin >> s >> t >> one >> ideal >> diff; one = min(one, 33ll); diff = min(diff, 33ll); rep(i, 32) id[i] = ideal % 2, ideal /= 2; reverse(id, id + 32); ll ans = solve(t) - solve(s - 1); printf("Case %d: %lld\n", cs + 1, ans); } return 0; }