bzoj2342 双倍回文【manacher+set】

来源:互联网 发布:维弗网络 编辑:程序博客网 时间:2024/06/04 23:48

解题思路:

开始以为只用r[i]是4的倍数的位置去检查其两侧是否也是回文就行了,但后面发现是错的,因为所求回文有可能在一个大回文内部,如aaabbaabbaaa,所以中间的r[i]会比更大;

后面看了下题解,还是太天真了。
枚举对称轴x,考虑用len(x,y)*4更新答案,则必须满足y-r[y]<=x,其中y<=x+r[x]/2。
那么我们按照y-r[y]排序后,依次把y插入set,每次询问比x+p[x]/2小的最大值就可以了。
由于我是加了’#’号的,写起来有些不同,不过大体思路是一样的。

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<ctime>#include<queue>#include<vector>#include<set>using namespace std;const int N=500005;int n,m,ans;int r[N<<1];char t[N],s[N<<1];struct node{    int x,id;    inline friend bool operator <(const node &a,const node &b)    {        return a.x<b.x;    }}a[N<<1];set<int>S;void manacher(){    int mx=0,po=0;    for(int i=1;i<=n;i++)    {        if(mx>i)r[i]=min(r[po*2-i],mx-i);        else r[i]=1;        while(s[i+r[i]]==s[i-r[i]])r[i]++;        if(i+r[i]>mx)po=i,mx=i+r[i];    }}int main(){    //freopen("lx.in","r",stdin);    //freopen("lx.out","w",stdout);    scanf("%d%s",&m,t+1);    s[0]='!';    for(int i=1;i<=m;i++)        s[++n]='#',s[++n]=t[i];    s[++n]='#',s[++n]='?';    manacher();    m=0;    for(int i=1;i<=n;i+=2)a[++m].x=i-r[i],a[m].id=i;    sort(a+1,a+m+1);    int j=1;    for(int i=1;i<=n;i+=2)    {        while(j<=m&&a[j].x<i)S.insert(a[j++].id);        ans=max(ans,(*--S.lower_bound(i+(r[i]+1)/2)-i)*2);    }    cout<<ans;    return 0;}
原创粉丝点击