洛谷 P4324 [JSOI2016]扭动的回文串 manacher+字符串hash

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/89014487

题目描述
JYY有两个长度均为 N N 的字符串 A A B B
一个扭动字符串 S ( i , j , k ) S(i,j,k) A A 中的第 i i 个字符到第 j j 个字符组成的子串与 B B 中的第 j j 个字符到第 k k 个字符组成的子串拼接而成。
比如,若 A = X Y Z A=’XYZ’ B = U V W B=’UVW’ ,则扭动字符串 S ( 1 , 2 , 3 ) = X Y V W S(1,2,3)= ’XYVW’
JYY 定义一个扭动的回文串为如下情况中的一个:
A A 中的一个回文串;
B B 中的一个回文串;
或者某一个回文的扭动字符串 S ( i , j , k ) S(i,j,k)
现在 JYY 希望找出最长的扭动回文串。

输入输出格式

输入格式:
第一行包含一个正整数 N N 。第二行包含一个长度为 N N 的由大写字母组成的字符串 A A 。第三行包含一个长度为 N N 的由大写字母组成的字符串 B B

输出格式:
输出的第一行一个整数,表示最长的扭动回文串。

输入输出样例

输入样例#1:
5
ABCDE
BAECB
输出样例#1:
5
说明

样例解释 最佳方案中的扭动回文串如下所示(不在回文串中的字符用 . 表示):

. B C . . .BC..
. . E C B ..ECB
对于所有的数据, 1 n 1 0 5 1≤n≤10^5

分析:
我们枚举答案回文串的中点 i i ,假设在 A A 串( B B 串同理)。维护两个指针,一个往左,一个往右,判断相不相等。如果不相等,再把右指针移动到B串。(就是能在A串中延伸就延伸,延伸不了在转B串)。
那么相当于A串中找一个以 i i 为中心的最长回文串,manacher解决。然后继续匹配部分可以用hash+二分解决。
求最长回文串其实也可以用hash+二分解决。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long

const int maxn=2e5+7;
const LL mod[2]={998244353,1e9+9};

using namespace std;

int n,len,ans;
char a[maxn],b[maxn],stra[maxn],strb[maxn];
int pa[maxn],pb[maxn];
LL ha[maxn][2],hb[maxn][2],bit[maxn][2];

void change(char *s,char *str)
{
    for (int i=1;i<=n;i++)
    {
        str[i*2-1]='#';
        str[i*2]=s[i];
    }
    str[n*2+1]='#';
}

void manacher(char *str,int *p)
{
    int pos=0;
    for (int i=1;i<=len;i++)
    {
        if (i<=pos+p[pos]) p[i]=min(p[2*pos-i],pos+p[pos]-i);
        while ((i+p[i]+1<=2*n+1) && (i-p[i]-1>=1) && (str[i+p[i]+1]==str[i-p[i]-1])) p[i]++;
        if (i+p[i]>=pos+p[pos]) pos=i;
    }
}

bool check(int la,int ra,int lb,int rb)
{
    LL ga[2],gb[2];
    for (int j=0;j<2;j++) ga[j]=(ha[ra][j]+mod[j]-ha[la-1][j]*bit[ra-la+1][j]%mod[j])%mod[j];
    for (int j=0;j<2;j++) gb[j]=(hb[lb][j]+mod[j]-hb[rb+1][j]*bit[rb-lb+1][j]%mod[j])%mod[j];
    return (ga[0]==gb[0]) && (ga[1]==gb[1]);
}

int solve(int x,int y)
{
    int l=1,r=min(x,len-y+1),ans=0;
    while (l<=r)
    {
        int mid=(l+r)/2;
        if (check(x-mid+1,x,y,y+mid-1)) l=mid+1,ans=mid;
                                   else r=mid-1;
    }
    return ans;
}

int main()
{
    scanf("%d",&n);
    scanf("%s",a+1);
    scanf("%s",b+1);
    change(a,stra);
    change(b,strb);
    len=2*n+1;
    manacher(stra,pa);
    manacher(strb,pb);
    bit[0][0]=bit[0][1]=1;	
    for (int i=1;i<=len;i++)
    {
        int c;
        if (stra[i]=='#') c=26;
                     else c=stra[i]-'A';
        for (int j=0;j<2;j++) ha[i][j]=(ha[i-1][j]*27+c)%mod[j];
        for (int j=0;j<2;j++) bit[i][j]=bit[i-1][j]*27%mod[j];
    }	
    for (int i=len;i>0;i--)
    {
        int c;
        if (strb[i]=='#') c=26;
                     else c=strb[i]-'A';
        for (int j=0;j<2;j++) hb[i][j]=(hb[i+1][j]*27+c)%mod[j];
    }	
    for (int i=1;i<=len;i++)
    {
        int l=i-pa[i]-1,r=i+pa[i]-1;
        ans=max(ans,pa[i]+solve(l,r));
    }
    for (int i=1;i<=len;i++)
    {
        int l=i-pb[i]+1,r=i+pb[i]+1;
        ans=max(ans,pb[i]+solve(l,r));
    }
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/89014487