[Poi2000]公共串 && hustoj2797

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

题目大意:给你几个串求出几个串中的最长公共子串。

题解:先看n最大才5,所以很容易想到暴力写法,因为最近在学后缀自动机就写写后缀自动机吧。

   我们将第一个串作为母串,然后在用其他的串与它进行匹配,并且记录下其匹配中每个状态的最大匹配数,答案则为每个状态的最大匹配的最小值中的最大值。。(绕晕了)

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

注意:我们在写的过程中,每到一个状态我们要不断跟新之前的状态答案,我们可以用dfs或者利用right数组的特性来更新,具体细节看看代码。

posted @ 2016-06-01 19:03  ACist  阅读(190)  评论(0编辑  收藏  举报