Problem
BZOJ3676【APIO2014】回文串
Time Limit: 20Sec
Memory Limit: 128MB
Description
给你一个由小写拉丁字母组成的字符串 s。我们定义 s 的一个子串的存在值为这个子串在 s 中出现的次数乘以这个子串的长度。
对于给你的这个字符串 s,求所有回文子串中的最大存在值。
输入只有一行,为一个只包含小写字母(a−z)的非空字符串 s。
Output
输出一个整数,表示所有回文子串中的最大存在值。
Input 1
Input 2
Sample Output
Output 1
Output 2
HINT
一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。
在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中:
- a出现4次,其出现值为4:4×1=4
- b出现2次,其出现值为2:2×1=2
- c出现1次,其出现值为1:1×1=1
- aba出现2次,其出现值为6:2×3=6
- aca出现1次,其出现值为3:1×3=3
- bacab出现1次,其出现值为5:1×5=5
- abacaba出现1次,其出现值为7:1×7=7
故最大回文子串出现值为7。
数据规模与评分
数据满足 1≤字符串长度≤3×105。
标签:回文自动机
Solution
回文自动机建出来直接统计答案。
具体回文自动机讲解参见 poursoul 的博客。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include <bits/stdc++.h> #define DICNUM 26 #define MAX_N 300000 using namespace std; typedef long long lnt; char s[MAX_N+5]; int cnt, trie[MAX_N+5][DICNUM], fail[MAX_N+5], end[MAX_N+5], len[MAX_N+5]; int newnode(int l) {len[++cnt] = l; return cnt;} void init() {fail[0] = newnode(-1), s[0] = '$';} int getf(int x, int l) {while (s[l-len[x]-1]^s[l]) x = fail[x]; return x;} int main() { scanf("%s", s+1), init(); int n = (int)strlen(s+1); for (int i=1, x=s[1]-'a', pre=0, cur=getf(pre,1); i<=n; end[pre=trie[cur][x]]++, x=s[++i]-'a', cur=getf(pre,i)) if (!trie[cur][x]) newnode(len[cur]+2), fail[cnt] = trie[getf(fail[cur], i)][x], trie[cur][x] = cnt; for (int i = cnt; i; i--) end[fail[i]] += end[i]; lnt ans = 0; for (int i = 1; i <= cnt; i++) ans = max(ans, 1LL*len[i]*end[i]); return printf("%lld", ans), 0; }
|