UVA 1633-Dyslexic Gollum 状态压缩DP

来源:互联网 发布:临沂知豆电动汽车销售 编辑:程序博客网 时间:2024/06/07 04:46

题意 :
输入n和k 求出长度为n的01串中有多少个不含长度至少为K的回文连续子串。
思路:
没有思路 看题解照着敲的。。。
首先 长的回文串由短的回文串构成,那么我们只需要避免构造的字符串出现长度为k和k+1的回文字符串就好了。
题目说的是01串 回文串长度最大是10 那么肯定是要用到状压DP的。
定义 dp[i][j] 表示长度为i的字符串后k位的二进制表示为j的合法字符串有多少个

分情况进行转移 i < k时

if(i<k){     judge[i+1][j<<1]=(judge[i+1][j<<1]+judge[i][j])%MOD;     judge[i+1][j<<1|1]=(judge[i+1][j<<1|1]+judge[i][j])%MOD;}

k<=i时 我们就有些麻烦了 我们要考虑j表示的串是否是回文串 j后面填上0或1后是否是回文串 每次都单独判断的话很耗时间 我们可以预处理一下

void init(){    memset(dp,-1,sizeof dp);    dp[1][1]=0;    dp[1][0]=0;    dp[2][0]=dp[2][3]=0;    for(int i=1; i<=11; i++)    {        int top=1<<i;        for(int j=0; j<top; j++)        {            if(dp[i][j]==0)            {                dp[i+2][j<<1]=0;                dp[i+2][fills(j,1,i)]=0;            }        }    }}// dpelse                {                    if(dp[k][j]==0)                        continue;                    int statu=j<<1;                    if(dp[k+1][statu]!=0)// 末尾填0                    {                        int cnt=statu;                        if(cnt>=(1<<k))                            cnt-=(1<<k);                        if(dp[k][cnt]!=0)                            judge[i+1][cnt]=(judge[i+1][cnt]+judge[i][j])%MOD;                    }                    if(dp[k+1][statu|1]!=0)                    {                        int cnt=statu|1;                        if(cnt>=(1<<k))                            cnt-=(1<<k);                        if(dp[k][cnt]!=0)                            judge[i+1][cnt]=(judge[i+1][cnt]+judge[i][j])%MOD;                    }                }

全部代码如下

# include<iostream># include<cstdio># include<cstring># include<algorithm>using namespace std;const int MOD=1e9+7;int judge[405][1<<12];// dp[i][j][k] 表示 前i位数 长度为j的后缀二进制表示为k的合法串有多少种int dp[15][1<<12];// 判断数组 二进制状态表示为j 长度为i的串是否为回文子串int fills(int j,int dig,int len){    if(dig)    {        return ((j<<1)+1)|(1<<(len+1));    }    else return j<<1;}void init(){    memset(dp,-1,sizeof dp);    dp[1][1]=0;    dp[1][0]=0;    dp[2][0]=dp[2][3]=0;    for(int i=1; i<=11; i++)    {        int top=1<<i;        for(int j=0; j<top; j++)        {            if(dp[i][j]==0)            {                dp[i+2][j<<1]=0;                dp[i+2][fills(j,1,i)]=0;            }        }    }}char str[100];int main(){    init();    int T;    cin>>T;    while(T--)    {        int n,k;        scanf("%d %d",&n,&k);        memset(judge,0,sizeof judge);        int ans=0;        judge[1][0]=judge[1][1]=1;        for(int i=1;i<=n;i++)        {            int top=1<<min(i,k);            for(int j=0;j<top;j++)            {                //printf("judge[%d][%d]=%d\n",i,j,judge[i][j]);                if(i<k)                {                    judge[i+1][j<<1]=(judge[i+1][j<<1]+judge[i][j])%MOD;                    judge[i+1][j<<1|1]=(judge[i+1][j<<1|1]+judge[i][j])%MOD;                }                else                {                    if(dp[k][j]==0)                        continue;                    int statu=j<<1;                    if(dp[k+1][statu]!=0)// 末尾填0                    {                        int cnt=statu;                        if(cnt>=(1<<k))                            cnt-=(1<<k);                        if(dp[k][cnt]!=0)                            judge[i+1][cnt]=(judge[i+1][cnt]+judge[i][j])%MOD;                    }                    if(dp[k+1][statu|1]!=0)                    {                        int cnt=statu|1;                        if(cnt>=(1<<k))                            cnt-=(1<<k);                        if(dp[k][cnt]!=0)                            judge[i+1][cnt]=(judge[i+1][cnt]+judge[i][j])%MOD;                    }                }                if(i==n)                    ans=(judge[i][j]+ans)%MOD;            }        }        cout<<ans<<endl;    }}
原创粉丝点击