题目地址:https://www.lydsy.com/JudgeOnline/problem.php?id=3676
回文树笔记:
字符串:abbaabba,下标从1开始存,建树如下:
节点0下面的都是偶数长度的回文串,节点1下面的都是奇数长度的回文串。
每个节点i(除0/1)表示1->(i-1)内以s[i-1]结尾的最长回文串,简记节点i表示的回文串,i为节点编号
- s[k]:存第k个插入的字符
- len[i] : 1->(i-1)内以s[i-1]结尾的最长回文串长度,特别的,len[0]=0, len[1]=-1
- cnt[i] : 记 1->(i-1)内以s[i-1]结尾的最长回文串为str, cnt[i]表示整个字符串中str出现的次数
- num[i] : 1->(i-1)内有多少个不同的回文串
- fail[i] : i
“失配” 后指向的位置,在i的父节点f[i]表示的回文串左右两侧添加c字符可得到新的回文串,在fail[i]的父节点f[fail[i]]的表示的回文串的两侧添加c字符也可得到新的回文串,等价于s[n-len[f[i]]-1]=s[n] , s[n-len[f[fail[i]]]-1]=s[n],n为当前已经插入的字符数目。且节点fail[i]表示的回文串是 节点i表示的回文串的最长后缀回文串,以s[i-1]结尾。如上图节点9表示的回文串是abbaabba,fail[9]=5,节点5表示的回文串是abba,是abbaabba的最长后缀回文串 - nxt[i][c] : 记录节点i表示的回文串左右两侧添加字符c形成的新回文串,该新的回文串对应的节点编号
题目:
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
【样例输入l】
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
7
【样例输出2]
4
ac代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300005;
typedef long long ll;
int fail[maxn], cnt[maxn], num[maxn], len[maxn], nxt[maxn][26], s[maxn];
int last, n, p;
char ss[maxn];
int newnode(int l) //l是节点对应的最长回文子串的长度
{
for(int i = 0; i < 26; i++)
nxt[p][i] = 0;
len[p] = l;
cnt[p] = 0;
num[p] = 0;
return p++;
}
void init()
{
p = 0, last = 0, n = 0, s[0] = -1;
newnode(0); // p=0的初始化
newnode(-1); // p = 1的初始化,之后 p = 2
fail[0] = 1;
fail[1] = 0;
}
int get_fail(int x)
{
while(s[n - len[x] - 1] != s[n])
x = fail[x];
return x;
}
void insert(int c) // c = ch - 'a'
{
s[++n] = c;
int cur = get_fail(last);
if(!nxt[cur][c])
{
int now = newnode(len[cur] + 2); //now表示当前节点编号
fail[now] = nxt[get_fail(fail[cur])][c];//此句和下面一句顺序一定不能倒!!
//因为nxt初始化为0,若当前节点表示的回文串是它自己,那么它的fail应该指向0,此时cur=1,get_fail(fail[cur])=1
nxt[cur][c] = now;
num[now] = num[fail[now]] + 1; //1->n所能形成的回文串数目+1
}
last = nxt[cur][c];//当前节点编号
cnt[last]++;//以last为结尾的最长回文子串对应的数目+1
}
void count()
{
for(int i = p - 1; i >= 0; i--) //从后往前更新
cnt[fail[i]] += cnt[i];
}
int main()
{
init();
scanf("%s", ss+1);//为了避免MLE,也可以边读字符边insert
int lenn = strlen(ss+1);
for(int i = 1; i <= lenn; i++)
insert(ss[i] - 'a');
count();
ll ans = 0;
for(int i = 0; i <= p - 1; i++)
ans = max(ans, 1LL * len[i] * cnt[i]);
printf("%lld\n", ans);
return 0;
}
【参考博客】:
https://blog.csdn.net/weixin_41190227/article/details/87271574