D. Count The Bits
数位DP
题意
给出 kkk 和 bbb,计算 [0,2b−1][0, 2^b-1][0,2b−1] 中所有 kkk 的倍数中有几个二进制 111。
题解
数位DP。
一个数加上 2i−12^i-12i−1 相当于在其二进制的第 iii 位添上 111。
记录下[0,2i−1][0,2^i-1][0,2i−1](i = 1,2,3……,b-1,b)的数转换为二进制后1的个数。iii 每增大 111 相当于 [0,2i−1−1][0,2^{i - 1}-1][0,2i−1−1] 中的每个数加上 2i−12^{i-1}2i−1 再加上原来的 [0,2i−1−1][0,2^{i - 1}-1][0,2i−1−1] 。
因为加上 2i−12^{i-1}2i−1 后余数会变。所以按照% k 所得的余数分类。
以k = 3 , b = 28 为例;
把[0,228−1][0,2^{28}-1][0,228−1]数划分为
[0,20−1][0,2^0-1][0,20−1] , [0,21−1][0,2^1-1][0,21−1] , [0,22−1][0,2^2-1][0,22−1] , [0,23−1][0,2^3-1][0,23−1]……([0,2i−1][0,2^i-1][0,2i−1])
建立一个f[130][1010]的数组,横坐标表示 iii,纵坐标 jjj 表示 %kkk 的余数,里面存 xxx 的个数(xϵ[0,2i−1]x\epsilon [0,2^i-1]xϵ[0,2i−1],xxx%kkk == jjj)。
当 iii = 0 时,只存在一个数 000,那么f[0][0] = 1;
当 iii = 1 时候,[1,1][1,1][1,1]可以用 [0,0][0,0][0,0] + 202^020 表示。那么原来的 0+1=1,% kkk 的余数就变成了1所以,f[1][1] = f[0][0] + f[0][1] = 1;
当 iii = 2 时候,[2,3][2,3][2,3]可以用 [0,1][0,1][0,1] + 212^121 表示。那么原来的 0+2=2,% kkk 的余数就变成了2所以,f[2][2] = f[1][2] + f[1][0] = 1 ;原来的1+2=3 , % kkk 的余数就变成了0,所以f[2][0] = f[1][1] + f[1][0] = 2; f[2][1] 还是原来的 f[1][1] = 1;
概括一下:f[i][j] = f[i - 1][j] + f[i-1][x] ( (x + 2i−12^{i-1}2i−1) % k == j )
建立一个g[130][1010]的数组,横坐标表示 iii,纵坐标 jjj 表示 %kkk 的余数,里面存 所有 xxx 转化为二进制后1的个数的总和 (xϵ[0,2i−1]x\epsilon [0,2^i-1]xϵ[0,2i−1],xxx%kkk == 纵坐标)。
g[i][j] = g[i-1][j] + g[i-1][x] + f[i-1][x] ( (x + 2i−12^{i-1}2i−1) % k == j )
g[i-1][j] 为原来就有的1数量。
纵坐标 为 xxx 的数 + 2i−12^{i-1}2i−1 后就变成了 %k == j 的数。
xxx 的数 + 2i−12^{i-1}2i−1 相当于在它们二进制的第 iii 位 添一个1,在[0,2i−1−1][0,2^{i-1}-1][0,2i−1−1]里有 f[i-1][j]个数,则在 [0,2i−1][0,2^i-1][0,2i−1] 要多添加 f[i-1][j] 个1,然后再加上g[i-1][x]原来就有的1的数量。
所以g[i][j] = g[i-1][j] + g[i-1][x] + f[i-1][x] ( (x + 2i−12^{i-1}2i−1) % k == j )
上代码
代码
#include<iostream>
using namespace std;
long long f[130][1010] = {},g[130][1010] = {};
int main()
{
const long long mod = 1e9+9;
long long a = 1,k,b;
cin>>k>>b;
f[0][0] = 1;
for (int i = 1;i<=b;i++)
{
for (int j = 0;j<=k-1;j++)
{
f[i][j] += f[i-1][j];
f[i][(j+a)%k] += f[i-1][j];
g[i][j] += g[i-1][j];
g[i][(j+a)%k] += g[i-1][j] + f[i-1][j];
}
for (int j = 0; j < k; ++j) f[i][j] %= mod, g[i][j] %= mod;
a = (a * 2) % k;
}
cout<<g[b][0];
}