zoukankan      html  css  js  c++  java
  • 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
    ",ans);
        return 0;
    }

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

    +本文作者:luyouqi233。               +

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

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

  • 相关阅读:
    inflate, findViewById与setContentView的差别与联系
    Android_程序未处理异常的捕获与处理
    八皇后问题
    兔子--改动Android Studio的快捷键,改动成eclipse的快捷键
    关于cocos2d-x 和安卓之间的相互调用
    《JavaScript》——DOM
    *Android 多线程下载 仿下载助手
    (LeetCode)两个链表的第一个公共节点
    MVC初了解
    URL编码总结
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9183416.html
Copyright © 2011-2022 走看看