题解:AT_abc359_d [ABC359D] Avoid K Palindrome
状压 dp 题。
思路
对于每个字符
- 如果
不为A
,那么它可以是B
。我们要把这个状态算进去。 - 如果
不为B
,那么它可以是A
。我们要把这个状态算进去。
令 A
,则
每次我们新加进来一个字符,都要把最前面的字符踢掉,然后把新的字符补进来。我们可以
- 若
不为A
, 函数返回 。 - 若
不为B
, 函数返回 。
特别地,如果 ?
,说明两种都可能,两种都要计算。
状态转移方程显然,因为可能有多个原来不相同的
注意到我们需要要求它不为回文串。因此在程序开始时,我们要预处理出所有可能的回文串对应的
代码
#include<iostream>
#define int long long
using namespace std;
int dp[1005][1055],whe[1055];
int n,k;
string s;
int mier[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int get(int _){
if(_%2)return _/2+1;
else return _/2;
}
char ask(int y){
if(y%2)return 'B';
return 'A';
}
int reget(char ch){
if(ch=='A')return 0;
return 1;
}
void init(){
int p=get(k);
for(int i=0;i<=mier[k]-1;i++){
string t=" ";
int q=i,cnt=k;
for(int i=1;i<=k;i++){
t[cnt--]=ask(q%2);
q/=2;
}
bool f=1;
for(int i=1;i<=p;i++){
if(t[i]!=t[k-i+1]){
f=0;
break;
}
}
if(f==1)whe[i]=1;
}
}
signed main(){
cin>>n>>k>>s;s=' '+s;
init();
if(s[1]!='B')dp[1][0]=1;
if(s[1]!='A')dp[1][1]=1;
for(int i=2;i<k;i++){
for(int j=0;j<mier[k];j++){
int y=0;
if(s[i]!='B')dp[i][j<<1]=(dp[i][j<<1]+dp[i-1][j])%998244353;
if(s[i]!='A')dp[i][(j*2)+1]=(dp[i][(j*2)+1]+dp[i-1][j])%998244353;
}
}
for(int i=k;i<=n;i++){
for(int j=0;j<mier[k];j++){
int y=0;
if(s[i]!='B'&&(!whe[(j*2)&(mier[k]-1)]))dp[i][(j*2)&(mier[k]-1)]=(dp[i][(j*2)&(mier[k]-1)]+dp[i-1][j])%998244353;
if(s[i]!='A'&&(!whe[((j*2)+1)&(mier[k]-1)]))dp[i][((j*2)+1)&(mier[k]-1)]=(dp[i][((j*2)+1)&(mier[k]-1)]+dp[i-1][j])%998244353;
}
}
int ans=0;
for(int i=0;i<mier[k];i++)ans+=dp[n][i];
cout<<ans%998244353;
return 0;
}
提示
- 代码中运用了位运算,是一种极好的卡常方法。
- 本题答案较大,需要开
long long
。
时间复杂度
预处理是
dp 是
总体复杂度为
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】