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。
之前得用后缀自动机+manacher的题目有了回文自动机(回文自动机可以看这篇博客:我是忧郁的“这篇博客”)瞬间变成板子题,代码长度--,代码难度--,正确率+=inf,PAM真的是神器。但是距离熟练运用可能还有一段距离。
大致思路很清晰了,回文自动机统计每一个本质不同回文串的出现次数和长度,复杂度为O(n)。代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 3e5 + 5;
namespace PAM {
char s[maxn];
int trie[maxn][26], sum[maxn], fail[maxn], len[maxn];
int cnt, pos, last;
void init() {
cnt = 1, pos = last = 0;
fail[0] = 1, len[0] = 0, len[1] = -1;
}
int getfail(int p) {
while(s[pos - len[p] - 1] != s[pos])
p = fail[p];
return p;
}
void add(int x) {
int id = s[x] - 'a';
int p = getfail(last);
if(!trie[p][id]) {
int now = ++cnt;
fail[now] = trie[getfail(fail[p])][id];
trie[p][id] = now;
len[now] = len[p] + 2;
}
last = trie[p][id];
++sum[last];
}
void push_up() {
for(register int i = cnt; i >= 0; --i)
sum[fail[i]] += sum[i];
}
void create() {
int sl = strlen(s);
for(register int i = 0; i < sl; ++i)
pos = i, add(i);
push_up();
}
long long cntans() {
long long ans = 0;
for(register int i = 2; i <= cnt; ++i)
ans = max(ans, 1LL * len[i] * sum[i]);
return ans;
}
}
int main() {
PAM::init();
scanf("%s", PAM::s);
PAM::create();
printf("%lld", PAM::cntans());
}
rockdu
没有帐号? 立即注册