我又来水sam了!!!



Description:

给出两个长度均不超过5000的字符串 , ,求这两个串中,都只出现一次的最短公共子串。

Solution:

这题可以 过,用 可以做到 ,但是本蒟蒻不会 ,所以无奈写了一发 ,时间复杂度

具体做法就是先建立两个串的共同的 ,然后对于每个节点记录一个 表示从根节点到当前节点的最短路径,然后求出每个节点分别在两个串中出现的次数 ,对于一个节点 ,如果有 ,那么就用 来更新


Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

char str1[5010]="\0";
char str2[5010]="\0";
int len1=0,len2=0;

struct trie
{
    int ch[26];
    int fa;
    int Link;
}tree[10010]={{{0},0,0}};
int tp=0;

int Np=0;
struct sam
{
    int ch[26];
    int lenth;
    int fail;
    int g1,g2;
    int Short;
}pot[20010]={{{0},0,0,0,0,0}};
int pp=0;
int S[10010]={0};
int rank[20010]={0};
int New[10010]={0};
int dui[10010]={0};
int duip=0;

void Add(int t,int c,int Pre)
{
    int cnt=New[Pre];New[t]=++pp;pot[New[t]].lenth=pot[New[Pre]].lenth+1;
    for(;cnt!=0 && pot[cnt].ch[c]==0;cnt=pot[cnt].fail)
        pot[cnt].ch[c]=New[t];
    if(cnt==0) pot[New[t]].fail=1;
    else
    {
        int q=pot[cnt].ch[c];
        if(pot[q].lenth==pot[cnt].lenth+1)
            pot[New[t]].fail=q;
        else
        {
            pp++;pot[pp]=pot[q];pot[pp].lenth=pot[cnt].lenth+1;
            pot[q].fail=pot[New[t]].fail=pp;
            for(;cnt!=0 && pot[cnt].ch[c]==q;cnt=pot[cnt].fail)
                pot[cnt].ch[c]=pp;
        }
    }
    return;
}

int main()
{
    int ans=2e9;
    scanf("%s",str1+1);
    scanf("%s",str2+1);
    len1=strlen(str1+1);
    len2=strlen(str2+1);
    tp=1;
    int cnt=1;
    for(int i=1;i<=len1;i++)
    {
        int c=str1[i]-'a';
        if(tree[cnt].ch[c]==0)
        {
            tree[cnt].ch[c]=++tp;
            tree[tp].fa=cnt;
        }
        cnt=tree[cnt].ch[c];
    }
    cnt=1;
    for(int i=1;i<=len2;i++)
    {
        int c=str2[i]-'a';
        if(tree[cnt].ch[c]==0)
        {
            tree[cnt].ch[c]=++tp;
            tree[tp].fa=cnt;
        }
        cnt=tree[cnt].ch[c];
    }
    tree[1].Link=0;
    New[0]=++pp;
    dui[++duip]=1;
    for(int i=1;i<=duip;i++)
    {
        int u=dui[i];
        for(int c=0;c<26;c++)
            if(tree[u].ch[c]!=0)
            {
                int v=tree[u].ch[c];
                dui[++duip]=v;
                tree[v].Link=++Np;
                Add(Np,c,tree[u].Link);
            }
    }
    cnt=1;
    for(int i=1;i<=len1;i++)
    {
        int c=str1[i]-'a';
        cnt=pot[cnt].ch[c];
        pot[cnt].g1++;
    }
    cnt=1;
    for(int i=1;i<=len2;i++)
    {
        int c=str2[i]-'a';
        cnt=pot[cnt].ch[c];
        pot[cnt].g2++;
    }
    for(int i=1;i<=pp;i++)
    {
        S[pot[i].lenth]++;
        pot[i].Short=2e9;
    }
    pot[1].Short=0;
    for(int i=1;i<=len1 || i<=len2;i++)
        S[i]+=S[i-1];
    for(int i=1;i<=pp;i++)
        rank[S[pot[i].lenth]--]=i;
    for(int i=1;i<=pp;i++)
    {
        int u=rank[i];
        for(int c=0;c<26;c++)
            if(pot[u].ch[c]!=0)
                pot[pot[u].ch[c]].Short=min(pot[pot[u].ch[c]].Short,pot[u].Short+1);
    }
    for(int i=pp;i>=2;i--)
    {
        if(pot[rank[i]].g1==1 && pot[rank[i]].g2==1)
            ans=min(pot[rank[i]].Short,ans);
        pot[pot[rank[i]].fail].g1+=pot[rank[i]].g1;
        pot[pot[rank[i]].fail].g2+=pot[rank[i]].g2;
    }
    if(ans==2e9)
        ans=-1;
    cout<<ans<<endl;
    return 0;
}