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
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。
Source
张天扬《APOI2014回文串 解题报告》2015国家集训队作业
把串建一个后缀自动机,然后算出每个点的right集合的大小和集合中的最大值,然后拿串在上面倒着跑(也就是反串正着跑)。
若当前到了串的第i个,在后缀自动机上的长度为l,当前节点为now,i+l>now->maxr>=i,则[i,now->maxr]构成的子串是一个回文串。
剩下的看看代码和论文吧…好恶心不知道怎么解释了……
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
typedef long long LL;
const int SZ = 600010;
struct sam_node{
sam_node *ch[30], *par;
int val,rcnt,rmax;
}T[SZ], *root, *last;
int Tcnt = 0;
sam_node* newnode(int x)
{
sam_node *k = T + (Tcnt ++);
k -> val = x;
memset(k -> ch,0,sizeof(k -> ch));
k -> par = 0;
k -> rcnt = 0;
k -> rmax = 0;
return k;
}
void insert(int x,int id)
{
sam_node *p = last,*np = newnode(last -> val + 1);
np -> rmax = id;
np -> rcnt = 1;
while(p && !p -> ch[x])
p -> ch[x] = np,p = p -> par;
if(!p)
np -> par = root;
else
{
sam_node *q = p -> ch[x];
if(q -> val == p -> val + 1)
{
np -> par = q;
}
else
{
sam_node *nq = newnode(p -> val + 1);
memcpy(nq -> ch,q -> ch,sizeof(q -> ch));
nq -> par = q -> par;
q -> par = np -> par = nq;
while(p && p -> ch[x] == q)
p -> ch[x] = nq,p = p -> par;
}
}
last = np;
}
int in[SZ];
queue<sam_node*> q;
void calc_right(char s[])
{
for(int i = 1;i < Tcnt;i ++)
{
sam_node *k = T + i;
in[k -> par - T] ++;
}
for(int i = 0;i < Tcnt;i ++)
if(!in[i])
q.push(T + i);
while(q.size())
{
sam_node *f = q.front(); q.pop();
if(!f -> par) continue;
f -> par -> rcnt += f -> rcnt;
f -> par -> rmax = max(f -> par -> rmax,f -> rmax);
if(!-- in[f -> par - T])
q.push(f -> par);
}
}
bool vis[SZ];
LL ask(char s[])
{
LL ans = 0;
int l = strlen(s + 1),len = 0;
sam_node *p = root;
for(int i = l;i >= 1;i --)
{
int c = s[i] - 'a' + 1;
while(p && !p -> ch[c])
p = p -> par,len = p -> val;
if(!p)
p = root,len = 0;
else
p = p -> ch[c],len ++;
if(i + len > p -> rmax)
{
if(i <= p -> rmax)
ans = max(ans,((LL)p -> rmax - i + 1) * p -> rcnt);
for(sam_node *fa = p -> par;fa && !vis[fa - T];fa = fa -> par)
{
vis[fa - T] = 1;
if(fa -> rmax >= i && fa -> rmax < i + fa -> val)
ans = max(ans,((LL)fa -> rmax - i + 1) * fa -> rcnt);
}
}
}
return ans;
}
char s[SZ];
void init()
{
root = newnode(0);
last = root;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
init();
scanf("%s",s + 1);
int l = strlen(s + 1);
for(int i = 1;i <= l;i ++)
insert(s[i] - 'a' + 1,i);
calc_right(s);
/* for(int i = 1;i < Tcnt;i ++)
{
sam_node *k = T + i;
printf("%d %d %d\n",k -> val,k -> rmax,k -> rcnt);
}*/
printf("%lld",ask(s));
return 0;
}