给出n<=400,k<=10,问长度为n且不含长度>=k的回文子串的01串有多少个
dp的过程有点像模拟构造的过程,可以发现一个长度>=k的回文子串一定包含一个长度为k或k+1的回文子串,所以构造的时候我们就防患于未然,禁止构造出长度为k或k+1的回文子串,那么更长的就不会出现了
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define MOD (1000000007)
using namespace std;
int n,k;
LL dp[420][1<<12];
bool vis[420][1<<12],hw[(1<<12)+10][20];
bool judge(int x,int len){
int i;len--;
bool flag=1;
for (i=0;i<=len/2;i++)
if (((x&(1<<i))>0)!=((x&(1<<(len-i)))>0)){
flag=0; break;
}
return flag;
}
LL Dfs(int cur,int x){
LL &ans=dp[cur][x];
if (vis[cur][x]) return ans;
vis[cur][x]=1;
if (cur==n) return ans=1;
int i,base;
for (i=0;i<=1;i++){
base=(x<<1)+i;
if (hw[base][k]||(cur>=k&&hw[base][k+1])) continue;
//上面这个特判容易漏
//后面加这个数后组成的新串的后缀不是长度为k或k+1的回文串
base=x&(~(1<<(k-1))); base<<=1; base+=i;//删首位,加末位
ans+=Dfs(cur+1,base); ans%=MOD;
}
return ans;
}
void Work(){
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
int i,j;
scanf("%d %d",&n,&k);
if (k>n){
cout<<(1<<n)<<endl; return;
}
LL ans=0;
for (i=0;i<(1<<(k-1));i++)
ans+=Dfs(k-1,i),ans%=MOD;
cout<<ans<<endl;
}
int main(){
// freopen("d.in","r",stdin);
// freopen("my.out","w",stdout);
int test_num; cin>>test_num;
int i,k;
for (i=0;i<1<<12;i++) for (k=1;k<=11;k++)
hw[i][k]=judge(i,k);
while (test_num--) Work();
return 0;
}