BZOJ 3676: [Apio2014]回文串
3676: [Apio2014]回文串
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2013 Solved: 863
[Submit][Status][Discuss]
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
【样例输入l】
abacaba
【样例输入2]
www
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
7
【样例输出2]
4
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
去这里自学了一下回文自动机(回文树?),赶脚贼牛逼 ( ఠൠఠ )ノ。然后,就真的是裸题了,23333.
当然,如果不用回文自动机也是可以做的。首先用Manacher求出来所有本质不同的回文子串,然后只需要知道每个在原串中出现的次数即可。方法有二,要么后缀数组,要么后缀自动机。后缀自动机的话好像需要倍增,添个$log$不是什么问题?后缀数组的话也需要二分+ST表,还是要添个$log$。
1 #include <cstdio> 2 3 namespace Pal 4 { 5 const int siz = 1000005; 6 int next[siz][26]; 7 int fail[siz]; 8 int cnt[siz]; 9 int len[siz]; 10 int str[siz]; 11 int last; 12 int tot; 13 int n; 14 15 inline int node(int l) 16 { 17 len[tot] = l; 18 return tot++; 19 } 20 21 inline void init(void) 22 { 23 node(0); 24 node(-1); 25 last = 0; 26 str[0] = -1; 27 fail[0] = 1; 28 } 29 30 inline int getFail(int t) 31 { 32 while (str[n - len[t] - 1] != str[n]) 33 t = fail[t]; 34 return t; 35 } 36 37 inline void insert(int c) 38 { 39 str[++n] = c; 40 int cur = getFail(last), now; 41 if (!next[cur][c]) 42 { 43 now = node(len[cur] + 2); 44 fail[now] = next[getFail(fail[cur])][c]; 45 next[cur][c] = now; 46 } 47 ++cnt[last = next[cur][c]]; 48 } 49 50 inline void count(void) 51 { 52 for (int i = tot - 1; ~i; --i) 53 cnt[fail[i]] += cnt[i]; 54 } 55 56 inline long long answer(void) 57 { 58 long long ret = 0; 59 60 for (int i = tot - 1; i > 1; --i) 61 if (ret < (long long)len[i] * cnt[i]) 62 ret = (long long)len[i] * cnt[i]; 63 64 return ret; 65 } 66 } 67 68 const int siz = 300005; 69 70 char s[siz]; 71 72 signed main(void) 73 { 74 scanf("%s", s); 75 76 Pal::init(); 77 78 for (char *t = s; *t; ++t) 79 Pal::insert(*t - 'a'); 80 81 Pal::count(); 82 83 printf("%lld\n", Pal::answer()); 84 }
@Author: YouSiki