bzoj2565: 最长双回文串
今天来学回文自动机的模板吧!Achen开心地告诉自己,然后打开了一道水题。
噫,这不是马拉车的水题嘛、、
第一反应,马拉车,然后线段树维护第i个字母结尾的最长回文串长度
然后其实做法应该是线性的,傻了吧,,,
考虑马拉车的时候往后拓展,容易想到每个点第一次被拓展到的时候的那个店就是以它为结尾的最长回文串的回文中心。
然后正反跑马拉车,枚举一下分割点统计答案即可,整体的时间复杂度也是O(n)的。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=2e5+7;
typedef long long LL;
using namespace std;
int ans,len,n,l[N],r[N],rad[N];
char s[N],ss[N];
void manacher(int ll[]) {
for(int i=1,k=0,j,now=0;i<n;) {
while(s[i-k-1]==s[i+k+1]) k++;
rad[i]=k;
while(now<n&&i+rad[i]>=now) {
ll[now]=i;
now++;
}
for(j=1;j<=k&&rad[i-j]!=rad[i]-j;j++)
rad[i+j]=min(rad[i-j],rad[i]-j);
k=max(k-j,0);
i+=j;
}
}
int is(char ch) {return ch>='a'&&ch<='z';}
int main() {
scanf("%s",ss);
int len=strlen(ss);
s[n++]='*'; s[n++]='&';
for(int i=0;i<len;i++) {
s[n++]=ss[i];
s[n++]='&';
}
s[n++]='#';
manacher(l);
memset(rad,0,sizeof(rad));
for(int i=0;i<=n/2;i++) swap(s[i],s[n-i-1]);
manacher(r);
for(int i=1;i<n-4;i++) if(is(s[i])) {
int a=i-r[i]+1,b=n-(i+2)-1-l[n-(i+2)-1]+1;
ans=max(ans,a+b);
}
printf("%d\n",ans);
return 0;
}
改天来补回文自动机的做法。
-------------------------------------------------------------------------------------
发现其实回文自动机的代码要更短,只是跑得贼慢,大概常数比较大。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
const int N=1e5+7;
typedef long long LL;
using namespace std;
char s[N];
int ans,n,last,tot,rt1,rt2,ch[N][26],len[N],fail[N],l[N],r[N],sz[N];
void init() {
len[rt1=0]=0; len[rt2=1]=-1;
tot=1; fail[rt1]=rt2; last=rt1;
memset(ch,0,sizeof(ch));
}
void insert(int tp,int c,int p[]) {
int x=last,y;
for(;(s[tp-len[x]-1]-'a')!=c;x=fail[x]);
if(!ch[x][c]) {
len[++tot]=len[x]+2;
for(y=fail[x];(s[tp-len[y]-1]-'a')!=c;y=fail[y]);
fail[tot]=ch[y][c]; // ch[x][c]=tot; fail[tot]=ch[y][c];
ch[x][c]=tot;
}
last=ch[x][c];
sz[last]++;
p[tp]=len[last];
}
int main() {
scanf("%s",s);
n=strlen(s);
init();
for(int i=0;i<n;i++)
insert(i,s[i]-'a',l);
for(int i=0;i<=n/2;i++) swap(s[i],s[n-i-1]);
init();
for(int i=0;i<n;i++) insert(i,s[i]-'a',r);
for(int i=0;i<n-1;i++)
ans=max(ans,r[i]+l[n-(i+1)-1]);
printf("%d\n",ans);
return 0;
}