UVa
题目链接:
保证不出现长度为 \(k\) 和 \(k+1\) 的回文串即可
状压 \(dp\),令 \(dp[i][s]\) 表示长度为 \(i\) 的串,第 \(i\) 位之前的 \(k\) 位为 \(s\) 的方案数
预处理出长度为 \(k\) 和 \(k+1\) 的回文串转移即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 410;
const int M = 1000000007;
int T, n, k;
int dp[maxn][1 << 11];
int is[1 << 12], is1[1 << 12];
int ksm(int i, int po){
int res = 1;
while(po){
if(po & 1) res = 1ll * res * i % M;
po >>= 1;
i = 1ll * i * i % M;
}
return res;
}
int a[15];
bool check(int x, int len){
memset(a, 0, sizeof(a));
int cnt = 0;
int tmp = x;
while(tmp){
a[++cnt] = tmp % 2;
tmp /= 2;
}
for(int i = 1 ; i <= len / 2 ; ++i){
if(a[i] != a[len-i+1]) return true;
}
return false;
}
void dfs(int d, int x){
if(d == k + 1){
if(check(x, k)) is[x] = 1;
}
if(d == k + 2){
if(check(x, k + 1)) is1[x] = 1;
return;
}
dfs(d + 1, x << 1); // + 0
dfs(d + 1, x << 1 | 1); // + 1
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
scanf("%d", &T);
while(T--){
scanf("%d%d", &n, &k);
if(k > n) {
printf("%d\n", ksm(2, n));
continue;
}
memset(is, 0, sizeof(is));
memset(is1, 0, sizeof(is1));
dfs(1, 0); // pre task
memset(dp, 0, sizeof(dp));
for(int s = 0 ; s < (1 << k) ; ++s){
if(is[s]) dp[k][s] = 1;
}
for(int i = k ; i < n ; ++i){
for(int s = 0 ; s < (1 << k) ; ++s){
if(is1[s << 1 | 1] && is[(s<<1|1)%(1<<k)]) dp[i+1][(s<<1|1)%(1<<k)] = (dp[i+1][(s<<1|1)%(1<<k)] + dp[i][s]) % M;
if(is1[s << 1] && is[(s<<1)%(1<<k)]) dp[i+1][(s<<1)%(1<<k)] = (dp[i+1][(s<<1)%(1<<k)] + dp[i][s]) % M;
}
}
int ans = 0;
for(int i = 0 ; i < (1 << k) ; ++i){
ans = (ans + dp[n][i]) % M;
}
printf("%d\n", ans);
}
return 0;
}