CF #244 (Div. 2)D

我又来水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;
}
<div id="wea_rich_text_default_font" style="font-family:微软雅黑;font-size:12;"><p><img alt="" src="/weaver/weaver.file.FileDownload?fileid=aaa9aee4717d33272bd7ea028fa03118b693919f23b18febf9f6cee1158e8f4cf027542c71c8cf98d63770ccdf3bd1750e6b92e28c43dccd4" /></p><div class="ckeditor-html5-video" data-widget="html5video" style="text-align:left"><video controls="controls" src="/weaver/weaver.file.FileDownload?fileid=aad6f413f83191673980c5ee24b412880d6b9e8703caca411faec3276fe8133f5fa7e34630ca89ace63770ccdf3bd175071362141037cfb4e&download=1" style="max-width:100%"> </video></div><table border="1" cellpadding="1" style="width:500px;"> <tbody> <tr> <td style="padding: 1px;">1</td> <td style="padding: 1px;">1</td> </tr> <tr> <td style="padding: 1px;">2</td> <td style="padding: 1px;">2</td> </tr> <tr> <td style="padding: 1px;">3</td> <td style="padding: 1px;">3<a href="http://localhost:8080/wui/index.html#/main/portal/portal-1-1?menuIds=0,1&menuPathIds=0,1&_key=zq8830" target="_blank">http://localhost:8080/wui/index.html#/main/portal/portal-1-1?menuIds=0,1&menuPathIds=0,1&_key=zq8830</a></td> </tr> </tbody></table><p>测试<a href="http://localhost:8080/wui/index.html#/main/portal/portal-1-1?menuIds=0,1&menuPathIds=0,1&_key=zq8830" target="_blank">http://localhost:8080/wui/index.html#/main/portal/portal-1-1?menuIds=0,1&menuPathIds=0,1&_key=zq8830</a></p><p> </p><p>修改一下吧 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq<img alt="" src="/weaver/weaver.file.FileDownload?fileid=a7617945ec5f52ec80aaa43ee8504de0a1b14d5eca4a98834494c85349762c626dec7ba8d0da277106ee600d27743f4e44f710fbddd167603" /></p></div>
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值