bzoj 3676: [Apio2014]回文串
Posted qt666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 3676: [Apio2014]回文串相关的知识,希望对你有一定的参考价值。
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
abacaba
【样例输入2]
www
Sample Output
7
【样例输出2]
4
HINT
一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。
在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中:
● a出现4次,其出现值为4:1:1=4
● b出现2次,其出现值为2:1:1=2
● c出现1次,其出现值为l:1:l=l
● aba出现2次,其出现值为2:1:3=6
● aca出现1次,其出现值为1=1:3=3
●bacab出现1次,其出现值为1:1:5=5
● abacaba出现1次,其出现值为1:1:7=7
故最大回文子串出现值为7。
【数据规模与评分】
数据满足1≤字符串长度≤300000。
Source
颓了好久了,终于想着来学一点新东西了;
其实回文自动机(or回文树)还是算一种比较simple的数据结构,其中每一个点代表的是一个回文串;
具体是用来统计:本质不同的回文串个数,以及,每个回文串的出现次数;
主要是要弄清几个数组的含义:
1.len[i]表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串)
2.next[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
3.fail[i]则指向i这个节点的最长后缀回文串(不包括本身)
4.cnt[i]表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
5.num[i]表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。
6.last指向新添加一个字母后所形成的最长回文串表示的节点。
(蒯的.....)
具体的话可以参见lcf2000的博客...
一开始有两个点,0表示偶数长度,1表示奇数长度的;
主要就是不断跳fail指针,直到S[n - len[last] - 1]==S[n];最后找到了一个cur点;
nxt[cur][c]有值说明以前已经有过这个回文串了,只需把次数加1;
如果不存在,则说明要新建一个节点表示新的回文串,且这个回文串的len显然等于len[cur]+2(len[1]=-1可以省一个特判),然后更新一下fail;
更新fail就是找到第一个使得S[n - len[last] - 1] == S[n]的last。
最后统计答案的时候从叶子节点开始加即可
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=500050; int gi() { int x=0,flag=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) flag=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar(); return x*flag; } int len[N],nxt[N][30],fail[N],tt,cnt[N],last; char s[N]; void insert(int c,int n){ int cur=last; while(s[n-len[cur]-1]!=s[n]) cur=fail[cur]; if(!nxt[cur][c]){ int now=++tt,la=fail[cur];len[now]=len[cur]+2; while(s[n-len[la]-1]!=s[n]) la=fail[la]; fail[now]=nxt[la][c],nxt[cur][c]=now; } last=nxt[cur][c];cnt[last]++; } int main(){ len[++tt]=-1;fail[0]=1; scanf("%s",s+1);int l=strlen(s+1); for(int i=1;i<=l;i++) insert(s[i]-‘a‘,i); ll ans=0;for(int i=tt;i>1;i--) cnt[fail[i]]+=cnt[i],ans=max(ans,1ll*len[i]*cnt[i]); printf("%lld\n",ans); }
以上是关于bzoj 3676: [Apio2014]回文串的主要内容,如果未能解决你的问题,请参考以下文章