BZOJ 3676 Apio2014 回文串
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
必备知识点:回文自动机写法;
这道题可以用manacher写,yzy学长讲了一晚上了,所以我把回文自动机写法描述一下。因为回文自动机建立的每一个节点都是一个回文串,而且会记录每个回文串出现的次数和长度,有了这两个条件,就足以解决这道题;
我们只需要枚举回文树中的每一个节点,找出len[i]*cnt[i]的最大值,并且输出,这就是这道题的全部,其实只需要一个回文自动机模板,就可以稍加修改,做出这道题。
下面上代码:
1 /************************************************************** 2 Problem: 3676 3 User: 1505125851 4 Language: C++ 5 Result: Accepted 6 Time:704 ms 7 Memory:36736 kb 8 ****************************************************************/ 9 10 #include<iostream> 11 #include<cstdio> 12 #include<cmath> 13 #include<cstring> 14 #include<cstdlib> 15 #include<string> 16 #include<algorithm> 17 #include<queue> 18 using namespace std; 19 const int MAXN=300005; 20 int len[MAXN],nxt[MAXN][26],fail[MAXN]; 21 int cnt[MAXN],num[MAXN]; 22 char s[MAXN]; 23 int n,m,l,r,w,k,last,p=0; 24 inline int getfail(int x) 25 { 26 while(s[n-len[x]-1]!=s[n]) x=fail[x]; 27 return x; 28 } 29 inline void add(int x) 30 { 31 last=getfail(last); 32 if(nxt[last][x]==0){ 33 len[++p]=len[last]+2; 34 fail[p]=nxt[getfail(fail[last])][x]; 35 nxt[last][x]=p; 36 num[p]=num[fail[p]]+1; 37 } 38 cnt[last=nxt[last][x]]++; 39 } 40 int main() 41 { 42 len[++p]=-1; 43 fail[0]=p; 44 gets(s+1); 45 m=strlen(s+1); 46 long long ans=-1; 47 for(int i=1;i<=m;i++){ 48 n++;add(s[i]-'a'); 49 } 50 for(int i=p;i>=2;i--){ 51 cnt[fail[i]]+=cnt[i]; 52 } 53 for(int i=2;i<=p;i++){ 54 ans=max(ans,1LL*len[i]*cnt[i]); 55 } 56 cout<<ans<<endl; 57 return 0; 58 }