题意:
找出长度为n、0和1个数相等、没有前导0且为k的倍数的二进制数的个数。
分析:
这道题要用动态规划来做。
设dp(zeros, ones, mod)为有zeros个0,ones个1,除以k的余数为mod的二进制数的个数,则状态转移方程为:
dp(zeros + 1, ones, (mod>>1) % k) += dp(zeros, ones, mod)
dp(zeros, ones + 1, ((mod>>1)+1) % k) += dp(zeros, ones, mod)
分别用记忆化搜索 和 递推的方式写了一遍,递推要比记忆化搜索快一半的时间。
1 #include <cstdio> 2 #include <cstring> 3 4 int n, k; 5 long long d[35][35][105]; 6 7 long long dp(int zeros, int ones, int mod) 8 { 9 if(zeros + ones > n || zeros > n/2 || ones > n/2) return 0; 10 if(d[zeros][ones][mod] != -1) return d[zeros][ones][mod]; 11 return d[zeros][ones][mod] = dp(zeros+1, ones, (mod<<1)%k) + dp(zeros, ones+1, (((mod<<1)%k)+1)%k); 12 } 13 14 int main() 15 { 16 //freopen("in.txt", "r", stdin); 17 18 int T; 19 scanf("%d", &T); 20 for(int kase = 1; kase <= T; ++kase) 21 { 22 scanf("%d%d", &n, &k); 23 24 if(n % 2 == 1 || k == 0) { printf("Case %d: 0\n", kase); continue; } 25 26 memset(d, -1, sizeof(d)); 27 d[n/2][n/2][0] = 1; 28 printf("Case %d: %lld\n", kase, dp(0, 1, 1)); 29 30 } 31 32 return 0; 33 }
1 #include <cstdio> 2 #include <cstring> 3 4 int n, k; 5 long long dp[35][35][105]; 6 7 int main() 8 { 9 //freopen("in.txt", "r", stdin); 10 11 int T; 12 scanf("%d", &T); 13 for(int kase = 1; kase <= T; ++kase) 14 { 15 scanf("%d%d", &n, &k); 16 17 if(n % 2 == 1 || k == 0) { printf("Case %d: 0\n", kase); continue; } 18 19 n /= 2; 20 memset(dp, 0, sizeof(dp)); 21 22 dp[0][1][1%k] = 1; 23 for(int i = 0; i <= n; i++) 24 for(int j = 0; j <= n; j++) 25 for(int m = 0; m < k; m++) 26 { 27 dp[i+1][j][(m<<1)%k] += dp[i][j][m]; 28 dp[i][j+1][((m<<1)+1)%k] += dp[i][j][m]; 29 } 30 31 printf("Case %d: %lld\n", kase, dp[n][n][0]); 32 33 } 34 35 return 0; 36 }