[bzoj4755][Jsoi2016]扭动的回文串

来自FallDream的博客,未经允许,请勿转载,谢谢。


JYY有两个长度均为N的字符串A和B。
一个“扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串与B中的第j个字符到第k个字符组成的子串拼接而成。
比如,若A=’XYZ’,B=’UVW’,则扭动字符串S(1,2,3)=’XYVW’。
JYY定义一个“扭动的回文串”为如下情况中的一个:
1.A中的一个回文串;
2.B中的一个回文串;
3.或者某一个回文的扭动字符串S(i,j,k)
现在JYY希望找出最长的扭动回文串。
n<=10^5
 
不难证明最长的扭动回文串是由一个中心的最长的回文串向两边延伸得到的。
所以先马拉车,然后二分+哈希判断即可。
还要判断一下两个串分别对称的情况。
#include<iostream>
#include<cstdio>
#include<vector>
#define MN 200000
#define rint register int
#define getchar() (*S++)
char BB[1<<26],*S=BB;
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9')  ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}
inline char Getchar()
{
    char c;
    do c=getchar(); while(c<'A'||c>'Z');
    return c;    
}

int n,mx,pos,Lt[MN+5],Rt[MN+5],ans=0;
unsigned int f[MN+5],F[MN+5],pw[MN+5];
char A[MN+5],B[MN+5];

int Solve(int Lt,int Rt)
{
    int l=1,r=min(Lt,n-Rt+1),mid,ans=0;
    while(l<=r)
    {
        mid=l+r>>1;
        unsigned int ha1,ha2;
        ha1=f[Lt-mid+1]-pw[mid]*f[Lt+1];
        ha2=F[Rt+mid-1]-pw[mid]*F[Rt-1];
        if(ha1==ha2)  ans=mid,l=mid+1;
        else r=mid-1;    
    }
    return ans;
}

int main()
{
    fread(BB,1,1<<26,stdin); 
    n=read();pw[0]=1;
    for(rint i=1;i<=n;++i) A[i<<1]=Getchar(),pw[i]=pw[i-1]*39;
    for(rint i=1;i<=n;++i) B[i<<1]=Getchar();
    for(rint i=1;i<=n+1;++i) A[i*2-1]=B[i*2-1]=']'; 
    mx=0,pos=0;n=n*2+1;
    for(rint i=n;i;--i) f[i]=f[i+1]*39+A[i]-'A'+1;
    for(rint i=1;i<=n;++i) F[i]=F[i-1]*39+B[i]-'A'+1;
    for(rint i=1;i<=n;++i)
    {
        if(i<=mx) Lt[i]=min(mx-i+1,Lt[2*pos-i]);
        else Lt[i]=1;
        while(i-Lt[i]>=1&&i+Lt[i]<=n&&A[i-Lt[i]]==A[i+Lt[i]]) ++Lt[i];
        if(Lt[i]+i-1>mx) mx=Lt[i]+i-1,pos=i;
        if(i&1) {if(Lt[i]>1)ans=max(ans,Solve(i-Lt[i],i+Lt[i]-2)+Lt[i]/2*2);}
        else  ans=max(ans,Solve(i-Lt[i],i+Lt[i]-2)+(Lt[i]-1)/2*2+1);    
        ans=max(ans,(Lt[i]-(i%2==0))/2*2+(i%2==0));
    }
    mx=n+1;pos=n+1;
    for(rint i=n;i;--i)
    {
        if(i>=mx) Rt[i]=min(i-mx+1,Rt[2*pos-i]);
        else Rt[i]=1;
        while(i-Rt[i]>=1&&i+Rt[i]<=n&&B[i-Rt[i]]==B[i+Rt[i]]) ++Rt[i];
        if(i-Rt[i]+1<mx) mx=i-Rt[i]+1,pos=i;
        if(i&1){ if(Rt[i]>1) ans=max(ans,Solve(i-Rt[i]+2,i+Rt[i])+Rt[i]/2*2);}
        else ans=max(ans,Solve(i-Rt[i]+2,i+Rt[i])+(Rt[i]-1)/2*2+1); 
        ans=max(ans,(Rt[i]-(i%2==0))/2*2+(i%2==0));
    }
    for(rint x=1;x<=n;++x) 
        if((!(x&1))&&A[x]==B[x]) ans=max(ans,Solve(x-2,x+2)+2);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/bzoj4755.html