1. 程式人生 > >bzoj2342 [Shoi2011]雙倍回文 (manacher)

bzoj2342 [Shoi2011]雙倍回文 (manacher)

最長回文 div 整數 class limit ret jpg LG sca

2342: [Shoi2011]雙倍回文

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3787 Solved: 1472
[Submit][Status][Discuss]

Description

技術分享圖片

Input

輸入分為兩行,第一行為一個整數,表示字符串的長度,第二行有個連續的小寫的英文字符,表示字符串的內容。

Output

輸出文件只有一行,即:輸入數據中字符串的最長雙倍回文子串的長度,如果雙倍回文子串不存在,則輸出0。


看了好長時間,太差了;
\(R[k]\)為以\(k\)為中心的最長回文串,\(x\)\(ww^Rww^R\)

對稱軸,\(y\)為右半部分\(ww^R\)對稱軸;
\(ch[x]\)\(ch[y]\)一定為特殊字符,所以一定滿足\(R[x]>=2(y-x)\)\(R[y]>=y-x\)
\(x+R[x]/2>=y\)\(x>=y-R[y]\)
所以把\(y\)\(y-R[y]\)排序,枚舉\(x\),把符合條件的\(y\)扔到\(set\)\(upper\)_\(bound\)一下就行了;
AC GET☆DAZE

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio> #include<vector> #include<cmath> #include<queue> #include<map> #include<set> #define N 1000039 #define mod 20070831 #define inf 0x3f3f3f3f #define ll long long using namespace std; int n,m,R[N],stp[N],ans; char ch[N],rea[N]; set<int> pos; set<int
>::iterator th; int force(int &id,int &mx,int r) { while(r<m) { if(rea[(id<<1)-r]!=rea[r]) break; R[id]++,mx=r++; } } void manacher() { int id=1,mx=1; for(int a=1,b;mx<m && a<m;a++) { if(a>=mx) force(id=a,mx,a+1); else { b=(id<<1)-a; if(R[b]<mx-a) R[a]=R[b]; else { R[a]=mx-a; force(id=a,mx,mx+1); } } } } bool cmp(int i,int j) { return i-R[i]<j-R[j]; } int main() { scanf("%d",&n); scanf(" %s",&ch); rea[0]='3',rea[m=2*n+2]='9'; for(int a=1;a<m;a++) { if(a&1) rea[a]='#'; else rea[a]=ch[(a>>1)-1]; stp[a]=a; } manacher(); sort(stp+1,stp+m,cmp); for(int a=1,b=1;a<m;a+=2) { while(b<m && stp[b]-R[stp[b]]<=a) { if(stp[b]&1) pos.insert(stp[b]); b++; } th=pos.upper_bound(a+R[a]/2); if(th!=pos.begin()) { th--; ans=max(ans,2*(*th-a)); } } printf("%d",ans); return 0; }

bzoj2342 [Shoi2011]雙倍回文 (manacher)