[GDOI2014]beyond 扩展KMP+并查集

题目等价于求给定两个长度都为 n n 的串 A,B A , B ,求一个最大的 L L 使得 A1..L A 1.. L B1..L B 1.. L 循环同构。
我们先对 A,B A , B 互相做一遍扩展KMP,记 Ai..n A i . . n B B 的LCP为 exai e x a i exb e x b 同理。
循环同构一定是存在 x x ,使得 A1..x=BLx+1..L , Ax+1..L=B1..Lx A 1.. x = B L − x + 1.. L   ,   A x + 1.. L = B 1.. L − x ,我们枚举 x x ,那么就是要在找到最大的 p[1..exax+1+1] p ∈ [ 1.. e x a x + 1 + 1 ] 满足 exbpx e x b p ≥ x 中,也就找到了一个 L=x+p L = x + p
我们用一个类似并查集的方法来维护这个,设 fai f a i i i 左边第一个合法的 p p ,考虑到 x x 是递增的,如果某个 exbj<x e x b j < x 就把 j j 缩掉即可。
代码:

#include
#include
#include
#define N 2000010
using namespace std;
int n,nxta[N],nxtb[N],exa[N],exb[N],fa[N];
char a[N],b[N];
void ex_kmp(char s[],char t[],int nxt[],int ex[])
{
    int st=1,ed=0;
    nxt[1]=n;
    for(int i=2;i<=n;i++)
    {
        if(nxt[i-st+1]1) {nxt[i]=nxt[i-st+1];continue;}
        ed=max(i-1,ed);
        for(int j=ed-i+1;ed1]==t[j+1];ed++,j++);
        st=i;nxt[i]=ed-i+1;
    }
    st=1;ed=0;
    for(int i=1;i<=n;i++)
    {
        if(nxt[i-st+1]1) {ex[i]=nxt[i-st+1];continue;}
        ed=max(i-1,ed);
        for(int j=ed-i+1;ed1]==t[j+1];ed++,j++);
        st=i;ex[i]=ed-i+1;
    }
}
int getfa(int v,int x)
{
    if(!v||exb[v]>=x) return v;
    return (fa[v]=getfa(fa[v],x));
}
int main()
{
    scanf("%d%s%s",&n,a+1,b+1);
    ex_kmp(a,b,nxtb,exa);
    ex_kmp(b,a,nxta,exb);
    for(int i=1;i<=n;i++)
        fa[i]=i-1;  
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        int tmp=getfa(exa[i+1]+1,i);
        //cout<
        if(tmp) ans=max(ans,tmp+i-1);
    }
    printf("%d",ans);
    return 0;
}

你可能感兴趣的:(并查集,kmp)