【BZOJ】2342: [Shoi2011]雙倍迴文-manacher&set
阿新 • • 發佈:2019-01-03
傳送門:bzoj2342
題解
迴文自動機很好做,但這裡講一下manacher的做法。
設偶迴文中心 的迴文半徑為 。
列舉迴文中心 ,找到最小的 滿足: 且
將回文中心按 升序排序並加入set, 列舉 時 所有 ,二分找出現存的最小的 即可。
程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
int n,m,f[N],rk[N],nt[N],ans;
char s[N],t[N];
set<int>st;
inline void manacher()
{
int i,j,ct=0,mx=0;
for(i=1;i<=n;++i){
for(j=mx>i?min(mx-i,f[(ct<<1)-i]):1;t[i-j]==t[i+j];++j);
f[i]=j;if(i+j>mx) mx=i+j,ct=i;
}m=0;
for(i=3;i<=n;i+=2) nt[++m]=f[i]>>1;
m--;
}
inline bool cmp(const int&x,const int&y){return x+nt[x]<y+nt[y];}
int main(){
int i,j,x;
scanf("%d%s",&m,s+1);
t[0]='!';
for(i=1;i<=m;++i) t[++n]='#',t[++n]=s[i];
t[++n]='#';t[++n]='?';
manacher();for(i=1;i<=m;++i) rk[i]=i,st.insert(i);
sort(rk+1,rk+m+1,cmp);
set<int>::iterator it;
for(i=j=1;i<=m;++i){
for(;j<=m && rk[j]+nt[rk[j]]<i;++j) st.erase(rk[j]);
x=*st.lower_bound(i-(nt[i]>>1));ans=max(ans,(i-x)<<2);
}
printf("%d\n",ans);
return 0;
}