1. 程式人生 > >【BZOJ】2342: [Shoi2011]雙倍回文(Manacher)

【BZOJ】2342: [Shoi2011]雙倍回文(Manacher)

manacher con spa 滿足 ans gin pac -i 代碼

題目

傳送門:QWQ

分析

(sb如我寫了發不知道什麽東西在洛谷上竟然水了84分

嗯咳

設$ i $為雙重回文的中心

如果$ j~i $ 可以被算作答案,只有滿足如下兩式:

  • $ p[j]+j \geq i $
  • $ 2*(i-j) \leq p[j] $

計算時我們先做一次馬拉車,然後按照 $ p[j]+j \geq i $排序,保證它的單調,接著把滿足$ 2*(i-j) \leq p[j] $扔進set裏詢問。

代碼

#include <bits/stdc++.h>
using namespace std;
const int
maxn=1050000; char s2[maxn],s[ maxn]; int p[ maxn], len; set<int> t; void Manacher(){ len=strlen(s2+1); for(int i=1;i<=len;i++){ s[i*2-1]=#; s[i*2]=s2[i]; } s[len=len*2+1]=#; int right=0, pos=0; for(int i=1;i<=len;i++){ if(i<right){ p[i]=min(p[2
*pos-i],right-i); } else p[i]=0; while(i+p[i]<=len &&i-p[i]>0 && s[i+p[i]]==s[i-p[i]]) p[i]++; if(i+p[i]>right){ right=i+p[i]; pos=i; } } } int q[maxn], f[maxn]; bool cmp(int a,int b){ return (a-f[a])<(b-f[b]); } int main(){
int n; scanf("%d%s",&n,s2+1); Manacher(); for(int i=1;i<=n;i++) q[i]=i, f[i]=(p[i*2+1]-1)/2; sort(q+1,q+1+n,cmp); int now=1,ans=0; for(int i=1;i<=n;i++){ while(now<=n&&q[now]-f[q[now]]<=i) { t.insert(q[now]); now++; } set<int>::iterator tmp=t.upper_bound(i+f[i]/2); if(tmp!=t.begin ()){ ans=max(ans,(*--tmp - i)); } } printf("%d\n",ans*4); return 0; } /* 17 qwertyuaabbaabbaa */

【BZOJ】2342: [Shoi2011]雙倍回文(Manacher)