[ABC359D]Avoid K Palindrome

错误思路一:

对于非?的字符,枚举,枚举范围是[i,i+k-1],找到所有的构成回文串的数量,用总数量减去构成回文串的数量,就是非回文串的数量,把这个加到答案里面,但是这个思路也是错的,为什么?因为这样会造成重复,这样只能保证枚举的范围里面没有回文串,如果枚举到下一个范围,这个范围的非回文会和上一个范围的非回文构成相同的子串,譬如ABAB.....BBAA,这个字符串是合法的,他在ABAB时会被枚举一次,在BBAA时仍然会被枚举一次,所以会造成重复

错误思路二:

设定\(f[i]\)表示前i个串能构成好串的数量,那么「i-k+1,i」要构成好串(不含回文),这个我们可以dfs查找,然后我们可以得到\(f[i]=f[i-k]+g(i-k+1,i)构成的好串的数量\),这样看似是正确的转移方程,其实是错误的,我可以举个例子来看
前i-k个以ABAB结尾,「i-k+1,i」是BABA这样的字符串,两边都是不能构成回文串的,但是当我们把他们拼接在一起的时候,他是可以构成回文串的ABABBABA,所以这样的思路是错误的,同样的,我对这个错误的思路进行一个补充,不止是对称的情况,还存在不对称的情况,也会出去连接的时候出现回文串,还有一个很重要的原因是,对于[i-k+1,i]这个区间,我只是求数量,并没有求是哪些串,所以我在拼接的时候根本无法进行,所以即使我修改状态为f[i][c]前i个串以c结束的好串的数量,也不行,因为我在拼接的时候,只计算了数量,没有描绘每个字符串的形态

正确思路:

我看到k<=10,当时我没有和状压DP挂上钩,说明状压DP的题做的比较少,其实这个题看到k<=10,同时看到只有A和B这两种字符,我们可以快速思考到状压DP,如果已经告知你是状压DP了,DP状态应该怎么设置呢?这个就比较自然
\(f[i][j]\)表示前i个中k个字符结束构成j能表示的好串的数量,那么\(f[i][j]=f[i][j]+f[i-1][k]\),当然,他需要满足如下条件:
假设A表示1,B表示0,那么如果s[i]='A',\((k<<1)|1==j\),如果是\(s[i]='B',(k<<1)==j\),在这里,有一个小细节需要注意一下,左移一位并不能直接左移,这里指的是在k位内左移,所以这里面有个细节很重要。如果s[i]='?'怎么办?因为?号可以取‘A’,也可以取‘B’,所以两种情况下都可以转移
第二,还有一个地方需要处理,我们要求k个子串不能是回文,所以对于每个i结束的k个子串,我们都需要处理一下哪些能用,哪些不能用,我用dfs处理的
最终的代码里,我并没有枚举k,因为k可以通过j位运算得到,所以我省了一层枚举
最终代码如下:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k;
char s[1005];
int cnt,st,dp[1005][15000],ans;
int mod=998244353;
bool f[1500],a[1005][1500];
bool check(int x){
	int g=0;
	int a[20];
	while(x){
		a[++g]=x%2;
		x=x/2;
	}
	while(g<=k){
		a[++g]=0;
	}
	int d=k;
	for(int i=1;i<=k/2;i++)
		if(a[i]!=a[d]){
			return true;
		}else{
			d--;
		}
	return false;
}
void dfs(int p,int py,int x){
	if(p==st-k){
		if(f[x]==true)
			a[st][x]=true;
		return;
	}
	if(s[p]=='B'){
		dfs(p-1,py+1,x);
	}
	if(s[p]=='A'){
		x=x|(1<<py);
		dfs(p-1,py+1,x);
	}
	if(s[p]=='?'){
		dfs(p-1,py+1,x);
		x=x|(1<<py);
		dfs(p-1,py+1,x);
	}
}
int main(){
	scanf("%d%d",&n,&k);
	scanf("%s",s+1);
	for(int i=0;i<((1<<k)-1);i++){
		if(check(i)) f[i]=true;
	}
	for(int i=k;i<=n;i++){
		cnt=0;
		st=i;
		dfs(st,0,0);
		a[i][0]=cnt;
	}
	for(int i=0;i<((1<<k)-1);i++){
		if(a[k][i])
			dp[k][i]=1;
	}	
	for(int i=k+1;i<=n;i++){
		for(int j=0;j<((1<<k)-1);j++){
			if(a[i][j]==true){
				if(s[i]=='A'||s[i]=='?'&&(j&1)==1){
					int sk=(j>>1);
					if(a[i-1][sk]==true) dp[i][j]=(dp[i][j]+dp[i-1][sk])%mod;
					sk=(j>>1)|(1<<(k-1));
					if(a[i-1][sk]==true) dp[i][j]=(dp[i][j]+dp[i-1][sk])%mod;
				}
				if(s[i]=='B'||s[i]=='?'&&(j&1)==0){
					int sk=(j>>1);
					if(a[i-1][sk]==true) dp[i][j]=(dp[i][j]+dp[i-1][sk])%mod;
					sk=(j>>1)|(1<<(k-1));
					if(a[i-1][sk]==true) dp[i][j]=(dp[i][j]+dp[i-1][sk])%mod;
				}
			}
		}
	}
	for(int i=0;i<((1<<k)-1);i++){
		if(a[n][i])
			ans=(ans+dp[n][i])%mod;
	}
	printf("%d",ans);
	return 0;
}
/**
7 4
AB?A?BA


**/
posted @ 2024-06-27 11:07  xinyimama  阅读(19)  评论(0编辑  收藏  举报