1. 程式人生 > >[BZOJ2341][Shoi2011]雙倍迴文 manacher+std::set

[BZOJ2341][Shoi2011]雙倍迴文 manacher+std::set

題目連結

發現雙倍迴文串一定是中心是#的迴文串。

所以考慮列舉#點。發現以\(i\)為中心的雙倍迴文的左半部分是個迴文串,其中心一定位於\(i-\frac{pal[i]-1}2\)\(i-1\)之間,而且越遠越好。所以我們用一個\(set\)來存一下目前為止迴文右端點\(\geq i\)的點,然後在\(set\)中找到大於等於\(i-\frac{pal[i]-1}2\)的最小值即可。

#include<bits/stdc++.h>
using namespace std;
#define fec(i,x,y) (int i=head[x],y=g[i].to;i;i=g[i].ne,y=g[i].to)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define isin(x,S) (((S)>>((x)-1))&1)
#define fi first
#define se second
#define pb push_back
template<typename I>inline void read(I&x){int f=0,c;while(!isdigit(c=getchar()))c=='-'?f=1:0;x=c&15;while(isdigit(c=getchar()))x=(x<<1)+(x<<3)+(c&15);f?x=-x:0;}
template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
typedef long long ll;typedef unsigned long long ull;typedef pair<int,int>pii;

const int N=500000+7;
int n,pal[N<<1],ans;char a[N],s[N<<1];

inline void Manacher(){
    int p=0,pos=0;
    for(int i=1;i<=n;++i){
        if(p>i)pal[i]=min(p-i+1,pal[(pos<<1)-i]);else pal[i]=1;
        while(s[i+pal[i]]==s[i-pal[i]])++pal[i];
        if(SMAX(p,i+pal[i]-1))pos=i;
    }
}

set<int>t;
vector<int>p[N<<1];
int main(){
    #ifdef hzhkk
    freopen("hkk.in","r",stdin);
    #endif
    scanf("%d%s",&n,a+1);
    s[0]=s[1]='#';
    for(int i=1;i<=n;++i)s[i<<1]=a[i],s[i<<1|1]='#';
    n=n<<1|1;
    Manacher();
    for(int i=1;i<=n;i+=2){
        t.insert(i);
        if(i+pal[i]-1<=n)p[i+pal[i]-1].pb(i);
        if(i&1)SMAX(ans,(i-*t.lower_bound(i-(pal[i]-1)/2))*2);
        for(vector<int>::iterator j=p[i].begin();j!=p[i].end();++j)t.erase(*j);
        for(int i=1;i<=n;++i)
    }
    printf("%d\n",ans);
}