NKOJ 2844 (APIO 2014)回文串(Manacher+后缀自动机+倍增/回文树)
2017-12-13 15:53
288 查看
P2844【APIO2014】回文串
问题描述考虑一个只包含小写英文字母的字符串s。我们定义s的一个字串t的“出现价值”为t在s中出现的次数乘以t的长度。请求出s的所有回文子串中的最大“出现价值”。
输入格式
输入只有一行,为一个只包含小写字母的非空字符串s。
输出格式
输出一个整数,为最大的回文子串价值。
样例输入1:
abacaba
样例输入2:
www
样例输出1:
7
样例输出2:
4
首先,此题是回文树模板题。
然后当然可以用朴素做法解决。
由于要查找回文串,考虑Manacher,然后需要查找回文串的出现次数,考虑后缀自动机。
显然的做法是在Manacher过程中,每找到一个回文串,就在自动机上从根开始跑,查找他的出现次数。
注意到事实上同样的回文串不需要多次运算,那么在Manacher过程中只需要在每次超出Max进行拓展时在自动机上查找即可。由于最多拓展n次,那么最多只需要查找n次。
但这样显然要超时,考虑优化查找速度,注意到每个串在自动机上都对应到了一个节点上,而parent树上该串必然是子节点串的后缀,那么考虑在parent树上倍增查找。
只需要在构建自动机的时候记录下每个字符为结尾,对应的节点编号,然后建完后每次从该结尾处倍增往上跳即可。查找复杂度log2n
代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #define N 666666 using namespace std; char s ,A ; int n,rad ,pos,MAX; int tot=1,rt=1,las=1,R ,Max ,pra [22],son [26],v ,S=19; int TOT,LA ,NE ,EN ; long long Ans; int NP(int x) { Max[++tot]=x; return tot; } void Ins(int t) { int p=las,q,np,nq; np=NP(Max[p]+1);v[np]=1; while(p&&!son[p][t])son[p][t]=np,p=pra[p][0]; if(!p)pra[np][0]=rt; else { q=son[p][t]; if(Max[q]==Max[p]+1)pra[np][0]=q; else { nq=NP(Max[p]+1); memcpy(son[nq],son[q],sizeof(son[q])); pra[nq][0]=pra[q][0]; pra[q][0]=pra[np][0]=nq; while(son[p][t]==q)son[p][t]=nq,p=pra[p][0]; } } las=np; } void ADD(int x,int y) { TOT++; EN[TOT]=y; NE[TOT]=LA[x]; LA[x]=TOT; } void DFS(int x) { int i,y; for(i=1;i<=S;i++)pra[x][i]=pra[pra[x][i-1]][i-1]; for(i=LA[x];i;i=NE[i]) { y=EN[i];DFS(y); v[x]+=v[y]; } } int Find(int k,int t) { int i,p=R[k]; for(i=S;i>=0;i--)if(Max[pra[p][i]]>=t)p=pra[p][i]; return p; } void Manacher() { int i,j,k,p; MAX=0;Ans=0;pos=0; for(i=1;i<=n;i++) { if(i>MAX)rad[i]=1; else rad[i]=min(MAX-i+1,rad[pos*2-i]); while(i-rad[i]>0&&i+rad[i]<=n&&A[i-rad[i]]==A[i+rad[i]]) { rad[i]++; k=i+rad[i]-2; if(A[k]!='%') { p=Find(k,rad[i]-1); Ans=max(Ans,1ll*v[p]*(1ll*rad[i]-1ll)); } } if(i+rad[i]-1>MAX)MAX=i+rad[i]-1,pos=i; } printf("%lld\n",Ans); } int main_main() { int i; scanf("%s",s); n=strlen(s); for(i=0;i<n;i++) { A[i+1<<1]=s[i]; A[(i+1<<1)-1]=A[(i+1<<1)+1]='%'; Ins(s[i]-'a');R[i+1<<1]=las; } for(i=1;i<=tot;i++)ADD(pra[i][0],i); n=n<<1|1;DFS(rt);Manacher(); } const int main_stack=16; char my_stack[128<<20]; int main() { __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory"); __asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp"); main_main(); __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp"); return 0; }
相关文章推荐
- [bzoj3676][Apio2014]回文串——Manacher+后缀自动机+倍增
- BZOJ3676 APIO2014回文串(manacher+后缀自动机)
- bzoj 3676: [Apio2014]回文串【后缀自动机+manacher】
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
- 【bzoj3676】[Apio2014]回文串 后缀自动机
- bzoj 3676: [Apio2014]回文串 manachar+后缀自动机+倍增(回文树)
- [manacher 后缀自动机 || 回文自动机] BZOJ 3676 [Apio2014]回文串
- [BZOJ3676][Apio2014]回文串-后缀自动机+Manacher | | 回文树
- 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习
- BZOJ 3676 UOJ 103 APIO 2014 后缀自动机 Manacher
- bzoj 3676: [Apio2014]回文串 回文自动机
- [BZOJ]3676: [Apio2014]回文串 回文自动机
- [BZOJ]3676 [APIO2014] 回文串 回文自动机
- bzoj 3676: [Apio2014]回文串 (回文自动机)
- [回文自动机] BZOJ3676 [Apio2014] . 回文串
- 【bzoj3676】[Apio2014]回文串 回文自动机
- 【回文自动机】bzoj3676 [Apio2014]回文串
- [bzoj3676][Apio2014]回文串 回文自动机(回文树)
- 字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串
- bzoj 3676: [Apio2014]回文串 回文自动机