回文自动机入门题
Posted violet-acmer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回文自动机入门题相关的知识,希望对你有一定的参考价值。
URAL-1960.Palindromes and Super Abilities
•题意
给你一个长度为 n 的字符串 s,下标从 1 开始;
输出 n 个数,第 i 个数表示 1~i 内有多少个本质不同的回文串;
•题解
回文自动机入门题;
定义 ans[ i ] 表示 1~i 共有 $ans_i$ 个本质不同的回文串;
$ans_i=ans_i-1$+第 i 个字符可形成本质不同的回文串 ? 1:0;
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+50; 4 5 char s[maxn]; 6 int ans[maxn]; 7 8 struct PAM 9 10 int tot; 11 int last; 12 int len[maxn]; 13 int fail[maxn]; 14 int son[maxn][30]; 15 16 int newNode(int Len) 17 18 for(int i=0;i < 30;++i) 19 son[tot][i]=0; 20 21 fail[tot]=0; 22 len[tot]=Len; 23 24 return tot++; 25 26 int getFail(int p,int i) 27 28 while(s[i-len[p]-1] != s[i]) 29 p=fail[p]; 30 31 return p; 32 33 void Init() 34 35 tot=0; 36 last=0; 37 38 newNode(0); 39 newNode(-1); 40 41 fail[0]=1; 42 43 void pam() 44 45 Init(); 46 47 int n=strlen(s); 48 for(int i=1;i < n;++i) 49 50 s[i]=s[i]-‘a‘+1; 51 int cur=getFail(last,i); 52 53 ans[i]=ans[i-1]; 54 if(!son[cur][s[i]]) 55 56 int now=newNode(len[cur]+2); 57 fail[now]=son[getFail(fail[cur],i)][s[i]]; 58 son[cur][s[i]]=now; 59 60 ans[i]++;///如果可以形成本质不同的字符串,ans[i]=ans[i-1]+1; 61 62 last=son[cur][s[i]]; 63 64 65 _pam; 66 int main() 67 68 scanf("%s",s+1); 69 s[0]=‘#‘; 70 int n=strlen(s); 71 72 ans[0]=0; 73 _pam.pam(); 74 75 for(int i=1;i < n;i++) 76 printf("%d%c",ans[i],i == n-1 ? ‘\n‘:‘ ‘); 77 78 return 0; 79
BZOJ-2565.最长双回文串
•题目描述
View Code问题描述: 顺序和逆序读起来完全一样的串叫做回文串。 比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。 输入长度为n的串S,求S的最长双回文子串T; 即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。 输入格式 一行由小写英文字母组成的字符串S。 输出格式 一行一个整数,表示最长双回文子串的长度。 样例输入 baacaabbacabb 样例输出 12 样例说明 从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。 数据规模及限制 对于10%的数据,2≤|S|≤103。 对于30%的数据,2≤|S|≤104。 对于100%的数据,2≤|S|≤105。 时间限制:2秒
•题解
枚举位置 i,求出以第 i 个字符为结尾的最长的回文串长度 $x_i$ 和以第 i+1 个字符为开始的最长回文串长度 $y_i+1$;
最终答案为 max$x_i+y_i+1$;
正向跑一边回文自动机便可求出以第 i 个字符为结尾的最长回文串的长度;
反向跑一边回文自动机便可求出以第 i 个字符为开始的最长回文串的长度;
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+50; 4 5 string s; 6 7 ///a[0][i]:正向跑一边,求出以第i个字符为结尾的最长回文串的长度 8 ///a[1][i]:反向跑一边,求出以第i个字符为开始的最长回文串的长度 9 int a[2][maxn]; 10 11 struct PAM 12 13 int tot; 14 int last; 15 int len[maxn]; 16 int fail[maxn]; 17 int son[maxn][30]; 18 19 int newNode(int Len) 20 21 for(int i=0;i < 30;++i) 22 son[tot][i]=0; 23 len[tot]=Len; 24 25 return tot++; 26 27 int getFail(int p,int i) 28 29 while(s[i-len[p]-1] != s[i]) 30 p=fail[p]; 31 32 return p; 33 34 void Init() 35 36 tot=0; 37 last=0; 38 39 newNode(0); 40 newNode(-1); 41 42 fail[0]=1; 43 44 45 void pam(int k) 46 47 Init(); 48 49 50 for(int i=1;i < s.size();++i) 51 52 s[i]=s[i]-‘a‘+1; 53 int cur=getFail(last,i); 54 55 if(!son[cur][s[i]]) 56 57 int now=newNode(len[cur]+2); 58 fail[now]=son[getFail(fail[cur],i)][s[i]]; 59 son[cur][s[i]]=now; 60 61 last=son[cur][s[i]]; 62 63 a[k][i]=len[last]; 64 65 66 _pam; 67 int main() 68 69 cin>>s; 70 s.insert(0,"#"); 71 72 _pam.pam(0); 73 reverse(s.begin()+1,s.end()); 74 _pam.pam(1); 75 76 int ans=0; 77 int n=s.size()-1; 78 for(int i=1;i < n;++i) 79 ans=max(ans,a[0][i]+a[1][n-i]); 80 81 printf("%d\n",ans); 82
以上是关于回文自动机入门题的主要内容,如果未能解决你的问题,请参考以下文章
bzoj千题计划306:bzoj2342: [Shoi2011]双倍回文 (回文自动机)