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

题目

传送门: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
*/

 

 

 

posted @ 2018-06-16 23:54  noble_(noblex)  阅读(187)  评论(0编辑  收藏  举报
/* */