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 }
回文树

 

posted @ 2018-06-12 20:37  杜宇一声  阅读(95)  评论(0编辑  收藏  举报