zoukankan      html  css  js  c++  java
  • BZOJ2946 Poi2000 公共串 【后缀自动机】

    Description

       给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
    

    任务:
    l 读入单词
    l 计算最长公共子串的长度
    l 输出结果

    Input

    文件的第一行是整数 n,1<=n<=5,表示单词的数量。接下来n行每行一个单词,只由小写字母组成,单词的长度至少为1,最大为2000。

    Output

    仅一行,一个整数,最长公共子串的长度。

    Sample Input

    3
    abcb
    bca
    acbc

    Sample Output


    先对第一个串建后缀自动机
    然后把其他的串拿到后缀自动机上面去跑
    得到每个节点的最大匹配长度
    然后用parent数上子节点的答案更新一下父亲节点的答案
    最后把每个串跑出来的结果取min
    对每个节点的最后结果取max就可以了


    #include<bits/stdc++.h>
    using namespace std;
    #define N 200010
    const int CHARSET_SIZE=26;
    struct Node{
      int ch[CHARSET_SIZE],prt;
      int maxl;
      Node(int maxl=0):ch(),prt(0),maxl(maxl){}
    }t[N];
    int root,last,cur;
    int topo[N],buc[N];
    int newnode(int maxl=0){t[++cur]=Node(maxl);return cur;}
    void init(){cur=0;root=last=newnode();}
    void extend(int c){
      int u=newnode(t[last].maxl+1),v=last;
      for(;v&&!t[v].ch[c];v=t[v].prt)t[v].ch[c]=u;
      if(!v){t[u].prt=root;}
      else if(t[v].maxl+1==t[t[v].ch[c]].maxl){
        t[u].prt=t[v].ch[c];
      }else{
        int n=newnode(t[v].maxl+1),o=t[v].ch[c];
        memcpy(t[n].ch,t[o].ch,sizeof(t[o].ch));
        t[n].prt=t[o].prt;
        t[o].prt=t[u].prt=n;
        for(;v&&t[v].ch[c]==o;v=t[v].prt)t[v].ch[c]=n;
      }
      last=u;
    }
    void toposort(){
      int maxv=0;
      for(int p=1;p<=cur;p++){
        maxv=max(maxv,t[p].maxl);
        buc[t[p].maxl]++;
      }
      for(int i=1;i<=maxv;i++)buc[i]+=buc[i-1];
      for(int p=1;p<=cur;p++)topo[buc[t[p].maxl]--]=p;
      fill(buc,buc+maxv+1,0);
    }
    char c[N];
    int ans[N],pic[N];
    int main(){
      init();
      int n;scanf("%d",&n); n--;
      scanf("%s",c+1);
      int len=strlen(c+1);
      for(int i=1;i<=len;i++)extend(c[i]-'a');
      toposort();
      for(int i=1;i<=cur;i++)ans[i]=t[i].maxl;
      while(n--){
        for(int i=1;i<=cur;i++)pic[i]=0;
        scanf("%s",c+1);
        len=strlen(c+1);
        int now=1,l=0;
        for(int i=1;i<=len;i++){
          int tmp=c[i]-'a';
          for(;now&&!t[now].ch[tmp];now=t[now].prt);
          if(!now)now=1,l=0;
          else l=min(l,t[now].maxl)+1,now=t[now].ch[tmp];
          pic[now]=max(pic[now],l);
        }
        for(int j=cur;j;j--){
          int k=topo[j];
          pic[t[k].prt]=min(t[t[k].prt].maxl,max(pic[t[k].prt],pic[k]));
          ans[k]=min(ans[k],pic[k]);
        }
      }
      int res=0;
      for(int i=1;i<=cur;i++)res=max(res,ans[i]);
      printf("%d",res);
      return 0;
    }
    
  • 相关阅读:
    设计模式
    【C/C++多线程编程之六】pthread相互排斥量
    J2EE的13个规范之(三) Servlet简单介绍
    .NET实现单点登录研究过程总结--【SSO】
    hdu4081 次小生成树变形
    eclipse代码提示框背景色改动
    Linux SO_KEEPALIVE属性,心跳
    [实战]MVC5+EF6+MySql企业网盘实战(20)——Bootstrap Paginator
    [工具]图片等比例压缩工具
    [工具类]视频音频格式转换
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9695650.html
Copyright © 2011-2022 走看看