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】
【样例输入2]
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
【样例输出2]
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[N]; char str[N],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; }