您的位置:首页 > 其它

[Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)

2018-04-12 14:53 399 查看

3676: [Apio2014]回文串

 

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 3396  Solved: 1568
[Submit][Status][Discuss]

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。

 

分析:

回文树眼题,但是我不会回文树QAQ

 

于是后缀自动机加manacher,构造出后缀自动机parent树后倍增每个点2^i能到达的点的dis值。 然后就可以做了。。。

AC代码:

 

# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
const int N = 3e5 + 12;
long long ans;
int ch[N << 1][26];
int dis[N << 1],fa[N << 1],w[N << 1],cnt = 1,len;
int que[N << 1],p[N << 1],dt,Log[19],g[N << 1][19],Id
;
char str
,s[N << 1];
int Sam(int c,int last)
{
int u = last,cur;
while(u && !ch[u][c])que[++que[0]] = u,u = fa[u];
if(!u)
{
cur = ++cnt;fa[cur] = 1;
while(que[0])ch[que[que[0]--]][c] = cur;
}
else
{
int v = ch[u][c];
if(dis[v] == dis[u] + 1)
{
cur = ++cnt;fa[cur] = v;
while(que[0])ch[que[que[0]--]][c] = cur;
}
else
{
int av = ++cnt;dis[av] = dis[u] + 1;cur = ++cnt;
while(que[0])ch[que[que[0]--]][c] = cur;
memcpy(ch[av],ch[v],sizeof ch[v]);
fa[av] = fa[v];fa[v] = fa[cur] = av;
while(u && ch[u][c] == v)ch[u][c] = av,u = fa[u];
}
}
dis[cur] = dis[last] + 1;
return cur;
}
void Manacher()
{
s[0] = '$';s[dt = 1] = '#';
for(int i = 1;i <= len;i++)s[++dt] = str[i],s[++dt] = '#';
int mx = 2,id = 1;p[0] = p[1] = 0;
for(int i = 2;i < dt;i++)
{
p[i] = min(p[2 * id - i],mx - i);
while(s[i + p[i] + 1] == s[i - p[i] - 1])
{
p[i]++;
if((i + p[i]) & 1)
{
int now = Id[(i + p[i] - 1) >> 1],L = ((i + p[i] - 1) >> 1) - ((i - p[i] + 1) >> 1) + 1;
for(int j = 18;~j;j--)if(dis[g[now][j]] >= L)now = g[now][j];
ans = max(ans,1LL * L * w[now]);
}
}
if(i + p[i] > mx)
{
id = i;
mx = i + p[i];
}
}
}
void init()
{
Log[0] = 1;for(int i = 1;i < 19;i++)Log[i] = Log[i - 1] << 1;
for(int i = 1;i <= cnt;i++)g[i][0] = fa[i];//这里考场上写成了<=len,结果得了90
for(int j = 1;j <= 18;j++)
for(int i = 1;i <= cnt;i++)
g[i][j] = g[g[i][j - 1]][j - 1];
}
int main()
{
scanf("%s",str + 1);len = strlen(str + 1);Id[0] = 1;
for(int i = 1;i <= len;i++)Id[i] = Sam(str[i] - 'a',Id[i - 1]),w[Id[i]]++;
for(int i = 1;i <= cnt;i++)p[dis[i]]++;
for(int i = 1;i <= len;i++)p[i] += p[i - 1];
for(int i = cnt;i >= 1;i--)que[p[dis[i]]--] = i;
for(int i = cnt;i >= 1;i--)w[fa[que[i]]] += w[que[i]];
init();Manacher();
printf("%lld\n",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: