BZOJ4755: [JSOI2016]扭动的回文串——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4755

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希望找出最长的扭动回文串。

我是一个大sb看错题不然这题就很sb了而且我还对字符串一窍不通。

先写manacher预处理两个串每个点的最大回文串半径。

然后(以枚举A串上的回文中心i为例),显然i的回文串一定要包含i在A的最大回文串(因为如果舍弃一些A的话,则有可能剩下的一点无法和B匹配,故选i在A的最大回文串一定不会使答案变差。)

二分长度哈希即可。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
const int N=2e5+5;
const int B=666233;
int n,ans,p[2][N];
char s1[N],s2[N];
ll ha[N],hb[N],qpow[N];
void manacher(char *s,int on){
    s[0]='@';
    for(int i=n;i>=1;i--)s[i<<1]=s[i];
    for(int i=1;i<=2*n+1;i+=2)s[i]='#';
    s[2*n+2]='?';int m=2*n+1;
    int mx=0,id;
    for(int i=1;i<=m;i++){
    if(i<mx)p[on][i]=min(p[on][2*id-i],mx-i);
    else p[on][i]=1;
    while(s[i+p[on][i]]==s[i-p[on][i]])p[on][i]++;
    if(i+p[on][i]>mx){
        mx=i+p[on][i];id=i;
    }
    ans=max(ans,p[on][i]-1);
    }
}
inline bool pan(int l1,int r1,int l2,int r2){
    ll h1=ha[r1]-ha[l1-1]*qpow[r1-l1+1];
    ll h2=hb[l2]-hb[r2+1]*qpow[r2-l2+1];
    return h1==h2;
}
int main(){
    scanf("%d%s%s",&n,s1+1,s2+1);
    manacher(s1,0);manacher(s2,1);n=2*n+1;
    qpow[0]=1;
    for(int i=1;i<=n;i++)qpow[i]=qpow[i-1]*B;
    for(int i=1;i<=n;i++)ha[i]=ha[i-1]*B+s1[i];
    for(int i=n;i>=1;i--)hb[i]=hb[i+1]*B+s2[i];
    for(int i=1;i<=n;i++){
    int l=0,r=min(i-p[0][i],n-(i+p[0][i]-2)+1);
    while(l<r){
        int mid=(l+r+1)>>1;
        int r1=i-p[0][i],l1=r1-mid+1,l2=i+p[0][i]-2,r2=l2+mid-1;
        if(pan(l1,r1,l2,r2))l=mid;
        else r=mid-1;
    }
    ans=max(ans,l+p[0][i]-1);
    }
    for(int i=1;i<=n;i++){
    
    int l=0,r=min(i-p[1][i]+2,n-(i+p[1][i])+1);
    while(l<r){
        int mid=(l+r+1)>>1;
        int r1=i-p[1][i]+2,l1=r1-mid+1,l2=i+p[1][i],r2=l2+mid-1;
        if(pan(l1,r1,l2,r2))l=mid;
        else r=mid-1;
    }
    int r1=i-p[1][i]+2,l1=r1-l+1,l2=i+p[1][i],r2=l2+l-1;
    ans=max(ans,l+p[1][i]-1);
    }
    printf("%d\n",ans);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-06-14 15:51  luyouqi233  阅读(351)  评论(0编辑  收藏  举报