[atARC094F]Normalization
考虑$s$能变成$t$的必要条件(假设$s\ne t$):
1.$s$中存在一对相邻字符不同
2.$|s|=|t|$且若将a-c对应为0-2,则字符模3同余;
3.$t$中存在一对相邻两个字符相同
同时,对于$|s|\ge 4$,这个充分条件也是必要条件,证明如下:
归纳,对于$|s|=4$暴力验证,否则考虑通过若干次操作将$s$首或尾的字符与$t$相同,然后删去这个字符
具体的构造:若初始相同,直接删去即可,否则强制$s_{2}=s_{3}=除去s_{1}和t_{1}的另一种字符$,然后通过$s_{4}$调整模数相等,再令$s_{5}=...=s_{|s|}=a$即可,先将$s[2,|s|]$变为该字符串,然后再操作一次即相同
同时为了保证第2个性质,若仅在首部出现相邻的相同字符,选择删去尾部,且由于$|s|\ge 4$,首尾相同的部分必然不会重复,因此合法
对于第一个条件直接判定(注意还有$s=t$的1种)即可,否则令$f[i][j][k][p]$表示$t$中前$i$个字符和模3为$j$,最后一个字符为$k$,是否出现过相邻字符相同的方案数,转移分类讨论即可
特别的,如果$s$中没有相邻两个字符,但$t=s$仍然是合法解,答案要加1
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define mod 998244353 5 int n,sum,ans,vis[3][3][3],f[N][3][3][2]; 6 char s[N]; 7 void dfs(int a,int b,int c){ 8 if (vis[a][b][c])return; 9 vis[a][b][c]=1; 10 ans++; 11 if (a!=b)dfs(3-a-b,3-a-b,c); 12 if (b!=c)dfs(a,3-b-c,3-b-c); 13 } 14 int main(){ 15 scanf("%s",s); 16 n=strlen(s); 17 if (n==2){ 18 printf("%d",1+(s[0]!=s[1])); 19 return 0; 20 } 21 if (n==3){ 22 dfs(s[0]-'a',s[1]-'a',s[2]-'a'); 23 printf("%d",ans); 24 return 0; 25 } 26 bool flag=0; 27 for(int i=1;i<n;i++) 28 if (s[i]!=s[0]){ 29 flag=1; 30 break; 31 } 32 if (!flag){ 33 printf("1"); 34 return 0; 35 } 36 for(int i=0;i<3;i++)f[0][i][i][0]=1; 37 for(int i=1;i<n;i++) 38 for(int j=0;j<3;j++) 39 for(int k=0;k<3;k++) 40 for(int l=0;l<3;l++) 41 for(int p=0;p<2;p++) 42 f[i][j][k][(p|(l==k))]=(f[i][j][k][(p|(l==k))]+f[i-1][(j+3-k)%3][l][p])%mod; 43 sum=0,ans=1; 44 for(int i=0;i<n;i++)sum=(sum+s[i]-'a')%3; 45 for(int i=1;i<n;i++)ans&=(s[i]!=s[i-1]); 46 for(int i=0;i<3;i++)ans=(ans+f[n-1][sum][i][1])%mod; 47 printf("%d",ans); 48 }