uva 1633 Dyslexic Gollum
题意:
给出n和k,求出长度为n的不包含长度大于等于k的回文串的01字符串的个数。
思路:
如果一个字符串包含长度为k的回文串,那么它肯定包含长度为k-1的回文串,所以考虑第i位的时候,只要前缀中不包含长度为k的回文串,就只需要考虑这一位使其满足条件,所以就可以进行递推dp了。
设dp[i][j]为长度为i的字符串且最后k位为j时满足的串的个数,因为k较小,所以可以进行状态压缩。
但是考虑k的长度是不行的,还需要考虑k+1才行,比如k = 4,j为0010,那么转移就可以转移到00100,后四位虽然满足,但是这5位显然是个回文串,所以需要考虑多一位。
首先预处理出长度为i,状态为j时是否时回文串。
bit数组用于保存2的i-1次方,即bit[i] = 2^(i-1)。
cal用于计算当前的最后k位。
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int N = 405; 6 const int K = 13; 7 const int mod = 1e9 + 7; 8 bool pal[K][1<<K]; 9 int bit[K]; 10 int dp[N][(1<<K)]; 11 bool check(int x,int k) 12 { 13 int b[K]; 14 memset(b,0,sizeof(b)); 15 int cnt = 0; 16 while (x) 17 { 18 b[cnt++] = x % 2; 19 x /= 2; 20 } 21 for (int i = 0;i < k/2;i++) 22 { 23 if (b[i] != b[k - i - 1]) return 0; 24 } 25 return 1; 26 } 27 int cal(int x,int y,int k) 28 { 29 if (x >= bit[k]) x -= bit[k]; 30 return x << 1 | y; 31 } 32 int main() 33 { 34 bit[0] = 0; 35 bit[1] = 1; 36 for (int i = 2;i < K;i++) bit[i] = bit[i-1] << 1; 37 for (int i = 1;i < K;i++) 38 { 39 for (int j = 0;j < (1<<i);j++) 40 { 41 if (check(j,i)) pal[i][j] = 1; 42 } 43 } 44 int t; 45 scanf("%d",&t); 46 while (t--) 47 { 48 int n,k; 49 scanf("%d%d",&n,&k); 50 if (k == 1) 51 { 52 puts("0"); 53 continue; 54 } 55 memset(dp,0,sizeof(dp)); 56 dp[0][0] = 1; 57 for (int i = 1;i <= n;i++) 58 { 59 for (int j = 0;j < (1 << min(i,k));j++) 60 { 61 if (!dp[i-1][j]) continue; 62 for (int x = 0;x < 2;x++) 63 { 64 int sta = cal(j,x,k); 65 if (i >= k && pal[k][sta]) continue; 66 if (i >= k + 1 && (pal[k+1][j<<1|x])) continue; 67 dp[i][sta] += dp[i-1][j]; 68 dp[i][sta] %= mod; 69 } 70 } 71 } 72 int ans = 0; 73 for (int i = 0;i < (1<<k);i++) 74 { 75 ans += dp[n][i]; 76 ans %= mod; 77 } 78 printf("%d\n",ans); 79 } 80 return 0; 81 } 82 /* 83 3 2 2 3 3 3 4 84 */
康复训练中~欢迎交流!