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;
}
posted @ 2021-07-31 10:25  Tartarus_li  阅读(55)  评论(0编辑  收藏  举报