CF #244 (Div. 2)D

来源:互联网 发布:如何设计一个软件 编辑:程序博客网 时间:2024/05/16 17:20

我又来水sam了!!!

   
   
   

Description:

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

   

Solution:

   这题可以 O(N2)过,用 SA可以做到 O(Nlog2N),但是本蒟蒻不会 SA,所以无奈写了一发 SAM,时间复杂度 O(N)

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

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;}
0 0
原创粉丝点击