zoukankan      html  css  js  c++  java
  • 【spoj1811 & spoj1812

    spoj1811  给两个长度小于100000的字符串 A 和 B,求出他们的最长公共连续子串。

    先将串 A 构造为 SAM ,然后用 B 按如下规则去跑自动机。
    用一个变量 lcs 记录当前的最长公共子串,初始化为0。
    设当前状态结点为 p,要匹配的字符为 c,若 go[c] 中有边,说明能够转移状态,则转移并 lcs++;
    若不能转移则将状态移动到 p 的 par ,如果仍然不能转移则重复该过程直到 p 回到根节点,并将 lcs 置为 0;
    如果在上一个过程中进入了能够转移的状态,则设 lcs 为当前状态的 val。
    为什么失配后要移向 par 呢?因为在状态 p 上失配说明该状态的 [min,max] 所表示字符串都不是 B 中的子串,但是比它们短的后缀仍有可能是 B 的子串,而 par 指针恰好指向了该状态的后缀。

     

    spoj1812  要求多个串的最长公共子串,n<=100000,10个串。

    本来想用广义sam,然后对每个点位压10位表示它能到哪些串,最后dfs一遍。
    20*10^5=10^6个点,时间压得很紧直接超时。

    参照上题做法,就把一个串A放进去,nlcs[x]维护当前串与A在自动机的x节点匹配的最大长度,lcs[x]维护前i个串。做完一个串后for一遍,x没有走到过的点lcs[x]=0,其余的lcs[x]=minn(lcs[x],nlcs[x]);

     

     

    spoj1811

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    using namespace std;
    
    const int N=2*100010;
    char a[N],b[N];
    int al,bl,tot,last,son[N][30],step[N],pre[N];
    
    int maxx(int x,int y){return x>y ? x:y;}
    
    int add_node(int x)
    {
        step[++tot]=x;
        return tot;
    }
    
    void extend(int ch)
    {
        int p=last,np=add_node(step[p]+1);
        while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];
        if(!p) pre[np]=1;
        else
        {
            int q=son[p][ch];
            if(step[q]==step[p]+1) pre[np]=q;
            else
            {
                int nq=add_node(step[p]+1);
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];
            }
        }
        last=np;
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        // freopen("me.out","w",stdout);
        memset(son,0,sizeof(son));
        memset(pre,0,sizeof(pre));
        memset(step,0,sizeof(step));
        tot=0;add_node(0);last=1;
        scanf("%s%s",a+1,b+1);
        al=strlen(a+1),bl=strlen(b+1);
        for(int i=1;i<=al;i++) extend(a[i]-'a'+1);
        int ch,x=1,ans=0,len=0;
        for(int i=1;i<=bl;i++)
        {
            ch=b[i]-'a'+1;
            while(x && !son[x][ch]) x=pre[x],len=step[x];
            if(x==0) x=1;
            if(son[x][ch]) x=son[x][ch],len++;
            
            ans=maxx(ans,len);
        }
        printf("%d
    ",ans);
        return 0;
    }

     

    spoj1812

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    using namespace std;
    
    const int N=2*100010;
    char s[15][N];
    int n,tot,last,son[N][30],step[N],pre[N],lcs[N],nlcs[N],l[15];
    bool vis[N];
    struct node{
        int x,y,next;
    }a[2*N];
    
    int maxx(int x,int y){return x>y ? x:y;}
    int minn(int x,int y){return x<y ? x:y;}
    
    int add_node(int x)
    {
        step[++tot]=x;lcs[tot]=x;
        return tot;
    }
    
    void extend(int ch)
    {
        int p=last,np=add_node(step[p]+1);
        while(p && !son[p][ch]) son[p][ch]=np,p=pre[p];
        if(!p) pre[np]=1;
        else
        {
            int q=son[p][ch];
            if(step[q]==step[p]+1) pre[np]=q;
            else
            {
                int nq=add_node(step[p]+1);
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                while(son[p][ch]==q) son[p][ch]=nq,p=pre[p];
            }
        }
        last=np;
    }
    
    void solve(int id)
    {
        memset(nlcs,0,sizeof(nlcs));
        memset(vis,0,sizeof(vis));
        int x=1,len=0,ch;
        for(int i=1;i<=l[id];i++)
        {
            ch=s[id][i]-'a'+1;
            while(x && !son[x][ch]) 
            {
                x=pre[x],len=step[x],vis[x]=1;
                nlcs[x]=maxx(nlcs[x],len);
            }
            if(x==0) x=1,vis[1]=1;
            if(son[x][ch]) x=son[x][ch],vis[x]=1,len++;
            nlcs[x]=maxx(nlcs[x],len);
        }
        for(int i=1;i<=tot;i++) 
            if(!vis[i]) lcs[i]=0;
            else lcs[i]=minn(lcs[i],nlcs[i]);
    }
    
    int main()
    {
        freopen("a.in","r",stdin);
        // freopen("me.out","w",stdout);
        memset(son,0,sizeof(son));
        memset(pre,0,sizeof(pre));
        memset(step,0,sizeof(step));
        tot=0;add_node(0);last=1;n=0;
        while(scanf("%s",s[++n]+1)!=EOF)
        {
            l[n]=strlen(s[n]+1);
        }n--;
        for(int i=1;i<=l[1];i++) extend(s[1][i]-'a'+1);
        for(int i=2;i<=n;i++) solve(i);
        int ans=0;
        for(int i=1;i<=tot;i++) ans=maxx(ans,lcs[i]);
        printf("%d
    ",ans);
        return 0;
    }

     

  • 相关阅读:
    0814防盗链访问控制代理
    0811Nginx访问日志设置
    0810Nginx安装
    0809LNMP架构介绍
    PHP安装
    mariaDB安装Apache安装(httpd)
    LAMP构架介绍
    shell基础知识(2)
    shell基础知识(1)
    yum更换国内源、yum下载rpm包、源码包安装
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/5836210.html
Copyright © 2011-2022 走看看