P9151 计数题
C1942huangjiaxu · · 题解
题目中的操作可以看做:
- 选择 2 个相邻的不同的数并删除。
- 选择 3 个相邻且相同的数,删掉其中 2 个。
那么最终对答案有贡献的
考虑构建这样一个自动机,每个点
假如
但这样不够,我们还要证明,每一个答案串
考虑构建自动机的过程其实是一个贪心的过程,我们只要证明,
证明也很简单,只要证明
自动机的边数是
以
对于
对于
我们要证明所有
首先
注意到不存在奇偶不同的
证明考虑归纳:
删除过程中产生
删除过程中产生
可以发现,不论
因为
时间复杂度
代码很好写:
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+5,P=998244353;
int T,n,f[N],nx[N][2],to[N][2],ans;
char s[N];
inline void Add(int &x,int y){
if((x+=y)>=P)x-=P;
}
void solve(){
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;++i)f[i]=0,s[i]-=48;
f[1]=1;
for(int i=3;i<=n;i+=2)if(s[i]!=s[1]&&s[i]==s[i-1]){
f[i]=1;
break;
}
for(int i=1;i<3;++i)for(int j=0;j<2;++j)nx[n+i][j]=to[n+i][j]=n+1;
for(int i=n;i;--i){
nx[i][0]=nx[i+2][0],nx[i][1]=nx[i+2][1];
to[i][0]=to[i+2][0],to[i][1]=to[i+2][1];
nx[i][s[i]]=i;
if(i<n&&s[i]==s[i+1])to[i][s[i]]=i+1;
}
ans=0;
for(int i=1;i<=n;++i)if(f[i]){
Add(f[nx[i+1][s[i]^1]],f[i]);
Add(f[to[i][s[i]]],f[i]);
if(!(n-i&1)&&(s[i]==s[n]||to[i][s[i]]<=n))Add(ans,f[i]);
}
printf("%d\n",ans);
}
int main(){
scanf("%d",&T);
while(T--)solve();
return 0;
}