【UVA1633】禁止的回文串(状压DP)

题意:

  输入正整数n和k(1<=n<=400,1<=k<=10),求长度为n的01串中有多少个不含长度至少为k的回文连续子串。例如,n=k=3时只有4个串满足条件:001,011,100,110。

 

分析:

  做这题的时候走了很多弯路,自以为想到了一个不用表示状态的dp,然而在保证不回文的时候就发现了很多问题。其实本题k的规模很小,所以应该要想到状压的。一个串中只要保证不含长度为k也不含长度为k+1的回文串,那么就不会出现大于k的回文串,所以我们构造的时候只要保证前面两个条件符合即可。

  状压记录后k的字符串,填新字符时保证不会构造出长度为k或k+1的回文串即可。

 

代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<iostream>
 6 using namespace std;
 7 #define Maxn 410
 8 #define Maxd 3010
 9 #define Mod  1000000007
10 
11 int f[Maxn][Maxd];
12 
13 bool check(int x,int kl)
14 {
15     int sl=1<<kl-1,sr=1;
16     for(int i=1;i<=kl/2;i++)
17     {
18         int l=x&sl,r=x&sr;
19         if((l&&(!r))||(!l&&r)) return 0;
20         sr<<=1;sl>>=1;
21     }
22     return 1;
23 }
24 
25 int main()
26 {
27     int T;
28     scanf("%d",&T);
29     while(T--)
30     {
31         int n,k;
32         scanf("%d%d",&n,&k);
33         if(k==1) {printf("0\n");continue;}
34         memset(f,0,sizeof(f));
35         f[0][0]=1;
36         int ans=0;
37         for(int i=1;i<=n;i++)
38         {
39             for(int j=0;j<=(1<<k+1)-1;j++) if(f[i-1][j]!=0)
40             {
41                 bool p0=1,p1=1;
42                 if(i>k&&check(j&((1<<k-1)-1),k-1))
43                 {
44                     if(j&(1<<k-1)) p1=0;
45                     else p0=0;
46                 }
47                 if(i>=k&&check(j&((1<<k-2)-1),k-2))
48                 {
49                     if(j&(1<<k-2)) p1=0;
50                     else p0=0;
51                 }
52                 int now=(j&((1<<k)-1))*2;
53                 if(p0) f[i][now]=(f[i][now]+f[i-1][j])%Mod;
54                 now=((j&((1<<k)-1))*2)+1;
55                 if(p1) f[i][now]=(f[i][now]+f[i-1][j])%Mod;
56             }
57         }
58         for(int i=0;i<=(1<<k+1)-1;i++)
59             ans=(ans+f[n][i])%Mod;
60         printf("%d\n",ans);
61     }
62     return 0;
63 }
uva1633

这题没有特判k=1的情况导致WA了很久,可能是我的代码风格太渣的问题TAT。

 

2016-03-04 13:25:02

转载于:https://www.cnblogs.com/Konjakmoyu/p/5241761.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值