zoukankan      html  css  js  c++  java
  • [Poi2000]公共串

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 #include <cstring>
     6 #define maxn 4005
     7 #define maxm 2005
     8 using namespace std;
     9 
    10 int n,m,tot,last,root,len,smin[maxn],sum[maxn],tmp[maxn],fa[maxn],son[maxn][26],dist[maxn];
    11 char st[maxm];
    12 struct Tsegment{
    13     int ans[maxn];
    14     void prepare(){tot=last=root=1;}
    15     int newnode(int x){dist[++tot]=x;return tot;}
    16     void add(int x){
    17         int p=last,np=newnode(dist[p]+1); last=np;
    18         for (;p&&!son[p][x];p=fa[p]) son[p][x]=np;
    19         if (p==0) fa[np]=root;
    20         else{
    21             int q=son[p][x];
    22             if (dist[p]+1==dist[q]) fa[np]=q;
    23             else{
    24                 int nq=newnode(dist[p]+1);
    25                 memcpy(son[nq],son[q],sizeof(son[q]));
    26                 fa[nq]=fa[q],fa[q]=fa[np]=nq;
    27                 for (;p&&son[p][x]==q;p=fa[p]) son[p][x]=nq;
    28             }
    29         }
    30     }
    31     void Fsort(){
    32         memset(sum,0,sizeof(sum));
    33         for (int i=1;i<=tot;i++) ans[i]=dist[i];
    34         for (int i=1;i<=tot;i++) sum[dist[i]]++;
    35         for (int i=1;i<=tot;i++) sum[i]+=sum[i-1];
    36         for (int i=1;i<=tot;i++) tmp[sum[dist[i]]--]=i;
    37     }
    38     void work(){
    39         scanf("%s",st+1),m=strlen(st+1);int x;
    40         memset(smin,0,sizeof(smin)),len=0,last=root;
    41         for (int i=1;i<=m;i++){
    42             x=st[i]-'a';
    43             if (son[last][x]) len++,last=son[last][x];
    44             else{
    45                 for (;last&&!son[last][x];) last=fa[last];
    46                 if (last==0) len=0,last=root;
    47                 else{
    48                     len=dist[last]+1,last=son[last][x];
    49                 } 
    50             }
    51             smin[last]=max(smin[last],len);
    52         }
    53         for (int i=tot;i>=1;i--){
    54             x=tmp[i];
    55             ans[x]=min(ans[x],smin[x]);
    56             if (fa[x]&&smin[x]) smin[fa[x]]=dist[fa[x]];
    57         }
    58     }
    59 }SAM;
    60 
    61 int main(){
    62     int ans=0;
    63     scanf("%d",&n),n--;
    64     SAM.prepare();
    65     scanf("%s",st+1),m=strlen(st+1);
    66     for (int i=1;i<=m;i++) SAM.add(st[i]-'a');
    67     SAM.Fsort();
    68     for (int i=1;i<=n;i++) SAM.work();
    69     for (int i=1;i<=tot;i++) ans=max(ans,SAM.ans[i]);
    70     printf("%d
    ",ans);
    71     return 0;
    72 }
    View Code

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2946

    http://begin.lydsy.com/JudgeOnline/problem.php?id=2797

    题目大意:给定n个字符串,n不大于5,每个字符串的长度不大于2000,求这n个字符串的最长公共子串的长度。

    做法:首先,这题还是可以用后缀数组+二分答案解决,那后缀自动机怎么解决呢?

    首先对其中一个串建立后缀自动机,其他串在上面匹配即可,失配则跳parent树。

    对于多串,我们在每个节点上记录一个信息,表示所有匹配的字符串匹配到该节点是最小的长度,每次用该字符串在SAM上每个点的最大匹配长度去更新要维护的信息(最小的长度),原因自己YY一下即可,木桶效应嘛。

    特别注意:在后缀自动机上匹配到一个节点时,那么它的所有祖先(通过fa一路可以到达的节点)都能匹配到其最大长度,每次记得通过一次dp得到。

    后缀自动机。

  • 相关阅读:
    分布式、集群的概念、区别
    Entity Framework学习
    QT入门
    Xcode插件开发
    函数指针
    c创建win窗口
    设置UITableView section间距
    使用谷歌地图时报一堆错的解决方法
    IOS地图及定位使用
    IOS判断手机型号
  • 原文地址:https://www.cnblogs.com/OYzx/p/5547661.html
Copyright © 2011-2022 走看看