BZOJ 3676: [Apio2014]回文串
3676: [Apio2014]回文串
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 904 Solved: 356
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
【样例输入1】
abacaba
【样例输入2】
www
Sample Output
【样例输出1】
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。
解题:回文树
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn = 300010; 5 const int N = 26; 6 struct PalindromicTree { 7 int next[maxn][N],fail[maxn],cnt[maxn]; 8 int s[maxn],len[maxn],last,tot,n; 9 int newnode(int length) { 10 cnt[tot] = 0; 11 memset(next[tot],0,sizeof next[tot]); 12 len[tot] = length; 13 return tot++; 14 } 15 int get_fail(int x) { 16 while(s[n - len[x] - 1] != s[n]) x = fail[x]; 17 return x; 18 } 19 void init() { 20 last = tot = n = 0; 21 newnode(0); 22 newnode(-1); 23 s[n] = -1; 24 fail[0] = 1; 25 } 26 void add(int c) { 27 c -= 'a'; 28 s[++n] = c; 29 int cur = get_fail(last); 30 if(!next[cur][c]) { 31 int now = newnode(len[cur] + 2); 32 fail[now] = next[get_fail(fail[cur])][c]; 33 next[cur][c] = now; 34 } 35 last = next[cur][c]; 36 cnt[last]++; 37 } 38 void count() { 39 for(int i = tot - 1; i > 1; --i) 40 cnt[fail[i]] += cnt[i]; 41 } 42 } PT; 43 char str[maxn]; 44 int main() { 45 while(~scanf("%s",str)) { 46 PT.init(); 47 for(int i = 0; str[i]; ++i) PT.add(str[i]); 48 PT.count(); 49 LL ret = 0; 50 for(int i = 2; i < PT.tot; ++i) 51 ret = max(ret,(LL)PT.len[i]*PT.cnt[i]); 52 printf("%lld\n",ret); 53 } 54 return 0; 55 }
夜空中最亮的星,照亮我前行