BZOJ2342: [Shoi2011]双倍回文
【传送门:BZOJ2342】
简要题意:
给出一个字符串,求出一个最长的子串满足不但由两个回文子串组成,而且本身也是一个回文串,且这两个回文子串不重叠,并且这两个回文子串长度为偶数,也就是说原子串的长度一定是4的倍数
题解:
之前学了Manacher,看到这道题,A了之后,忘写博客,现在补一下
先对原字符串搞一下Manacher,然后就for一遍,枚举构成双倍回文子串的中间点,然后再用一个for来向前找左端点,同时判断是否有相应的右端点与之对应
参考代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int p[1100000]; char s[510000],now[1100000]; int n; int Manacher() { for (int i=1;i<=n;i++) now[2*i-1]='#',now[2*i]=s[i]; n=n*2+1; now[n]='#'; int pos=0,R=0; for(int i=1;i<=n;i++) { int j=2*pos-i; if(i<=R) p[i]=min(p[j],R-i); else p[i]=1; while(1<=i-p[i]&&i+p[i]<=n&&now[i-p[i]]==now[i+p[i]]) p[i]++; if(i+p[i]>R){pos=i;R=i+p[i];} } } int main() { scanf("%d",&n); scanf("%s",s+1); Manacher(); int ans=0; for(int i=1;i<=n;i+=2) { if(p[i]%2==0||ans>=p[i]-1) continue; for(int j=i-(p[i]-1)/2;j<i;j++) { if((i-j)*2<=ans) break; if((i-j)%2!=0) continue; if(j+p[j]-1>=i){ans=max(ans,(i-j)*2);break;} } } printf("%d\n",ans); return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚