【POJ-2774】Long Long Message 后缀数组 最长公共子串(出现两次不重叠子串)

Long Long Message

题意

给出两个字符串,让找出最长的公共子串

思路

把两个字符串合起来,做最长不重叠子串即可。

[poj 1743] Musical Theme 后缀数组 or hash

数组开二倍

代码

/*Gts2m ranks first in the world*/
#define pb push_back
#define stop system("pause")
#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<string>
#include<algorithm>
#include<iostream>
// #include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
typedef unsigned long long ull;

char s[N],t[N];
int sa[N],rk[N],oldrk[N],cnt[N],pos[N],ht[N];
int n,m;
bool cmp(int a,int b,int k)
{
    return oldrk[a]==oldrk[b]&&oldrk[a+k]==oldrk[b+k];
}
void getsa()
{
    m=122;
    memset(cnt,0,sizeof(cnt));
    for(int i=1;i<=n;i++) ++cnt[rk[i]=s[i]];
    for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
    for(int i=n;i;i--) sa[cnt[rk[i]]--]=i;
    // rk[n+1]=0;
    for(int k=1;k<=n;k<<=1)
    {
        int num=0;
        for(int i=n-k+1;i<=n;i++) pos[++num]=i;
        for(int i=1;i<=n;i++) if(sa[i]>k) pos[++num]=sa[i]-k;
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=n;i++) ++cnt[rk[i]];
        for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for(int i=n;i;i--) sa[cnt[rk[pos[i]]]--]=pos[i];
        num=0;
        memcpy(oldrk,rk,sizeof(rk));
        for(int i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],k)?num:++num;
        if(num==n) break;
        m=num;
    }
    for(int i=1;i<=n;i++) rk[sa[i]]=i;
    int k=0;
    for(int i=1;i<=n;i++)
    {
        if(k) --k;
        while(s[i+k]==s[sa[rk[i]-1]+k]) ++k;
        ht[rk[i]]=k;
    }
}
int lens,lent;
int judge(int x)
{
    int minn=sa[1],maxn=sa[1];
    for(int i=2;i<=n;i++)
    {
        if(ht[i]>=x)
        {
            minn=min(minn,sa[i]);
            maxn=max(maxn,sa[i]);
        }
        else minn=maxn=sa[i];
        if(minn+x-1<=lens&&maxn>lens+1) return 1;
    }
    return 0;
}
int main()
{
    scanf("%s%s",s+1,t+1);
    lens=strlen(s+1),lent=strlen(t+1);
    n=lens;
    s[++n]=0;
    for(int i=1;i<=lent;i++) s[++n]=t[i];
    getsa();
    int l=1,r=min(lens,lent),ans=0;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(judge(mid))
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    printf("%d\n",ans);
    // stop;
    return 0;
}
posted @ 2020-05-13 21:35  Valk3  阅读(109)  评论(0编辑  收藏  举报