您的位置:首页 > 编程语言 > Go语言

UVA 1633-Dyslexic Gollum 状态压缩DP

2017-08-18 20:23 281 查看
题意 :

输入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;
}
}
}
}
// dp
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;
}
}


全部代码如下

# 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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: