回文串 / Palindromes
题目链接:luogu P3649 / UOJ #103
题目大意
给你一个字符串,要你找一个分数最大的回文子串。
一个子串的分数是它的长度乘它在字符串中出现的次数。
思路
看到回文串想到 Manacher 和 PAM。
然后发现要统计回文串出现次数,自然想到 Manacher 的
n
u
m
num
num 数组。
然后就求出来,然后每个暴力看取最大值就可以了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
struct PAM {
int nxt[26], trans;
int num, sum, fail, len;
}t[300002];
int sn, lst, tot;
char s[300001];
ll ans;
int get_new(int l) {
t[++tot].len = l;
for (int i = 0; i < 26; i++) t[tot].nxt[i] = 0;
t[tot].num = t[tot].sum = t[tot].fail = t[tot].trans = 0;
return tot;
}
int get_fail(int x, int pl) {
while (s[pl - t[x].len - 1] != s[pl]) x = t[x].fail;
return x;
}
void count() {
for (int i = tot; i >= 2; i--)
t[t[i].fail].num += t[i].num;
}
int main() {
scanf("%s", s + 1);
sn = strlen(s + 1);
tot = 1; lst = 0;
t[0].fail = 1; t[1].fail = 0;
t[0].len = 0; t[1].len = -1;
for (int i = 1; i <= sn; i++) {
int pre = get_fail(lst, i), go = s[i] - 'a';
if (!t[pre].nxt[go]) {
int now = get_new(t[pre].len + 2);
t[now].fail = t[get_fail(t[pre].fail, i)].nxt[go];
t[pre].nxt[go] = now;
t[now].sum = t[t[now].fail].sum + 1;
if (t[now].len <= 2) t[now].trans = t[now].fail;
else {
int tmp = t[pre].trans;
while (s[i - t[tmp].len - 1] != s[i] || ((t[tmp].len + 2) << 1) > t[now].len)
tmp = t[tmp].fail;
t[now].trans = t[tmp].nxt[go];
}
}
lst = t[pre].nxt[go];
t[lst].num++;
}
count();
for (int i = 2; i <= tot; i++)
ans = max(ans, 1ll * t[i].num * t[i].len);
printf("%lld", ans);
return 0;
}