spoj 1812 LCS2(SAM+DP)

求若干个串的最长公共子串。

SAM+DP

先拿个串建个SAM,然后用后面的串匹配,每次将所有的匹配长度记录在状态上取min,然后对所有状态取max即答案。

需要更新fa,因为fa[p]一定比p更优,但匹配的时候可能只更新了p而没有更新fa[p],所以还需要递推一边。

注意mn[p]初始化为l[p]

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int N = 5*1e5+10;
 6 
 7 char s[N];
 8 int sz,last,root,l[N],ch[N][26],fa[N],mn[N],mx[N];
 9 int b[N],cnt[N];
10 void add(int x) {
11     int c=s[x]-'a';
12     int p=last,np=++sz; last=np; 
13     l[np]=mn[np]=x+1;
14     for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
15     if(!p) fa[np]=root;
16     else {
17         int q=ch[p][c];
18         if(l[p]+1==l[q]) fa[np]=q;
19         else {
20             int nq=++sz; l[nq]=mn[nq]=l[p]+1;
21             memcpy(ch[nq],ch[q],sizeof(ch[q]));
22             fa[nq]=fa[q];
23             fa[np]=fa[q]=nq;
24             for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
25         }
26     }
27 }
28 
29 int main() {
30     root=last=++sz;
31     scanf("%s",s);
32     int len=strlen(s);
33     for(int i=0;i<len;i++) add(i);
34     for(int i=1;i<=sz;i++) cnt[l[i]]++;
35     for(int i=1;i<=len;i++) cnt[i]+=cnt[i-1];
36     for(int i=1;i<=sz;i++) b[cnt[l[i]]--]=i;
37     while(scanf("%s",s)==1) {
38         int p=root; len=0;
39         for(int i=0;s[i];i++) {
40             int c=s[i]-'a';
41             if(ch[p][c]) { len++; p=ch[p][c]; }
42             else {
43                 while(p&&!ch[p][c]) p=fa[p];
44                 if(!p) { len=0; p=root; }
45                 else { len=l[p]+1; p=ch[p][c]; }
46             }
47             if(len>mx[p]) mx[p]=len;
48         }
49         for(int i=sz;i;i--) {
50             p=b[i];
51             if(mx[p]<mn[p]) mn[p]=mx[p];
52             if(fa[p] && mx[fa[p]]<mx[p]) mx[fa[p]]=mx[p];
53             mx[p]=0;
54         }
55     }
56     int ans=0;
57     for(int i=1;i<=sz;i++)
58         if(mn[i]>ans) ans=mn[i];
59     printf("%d",ans);
60     return 0;
61 }

 

先将一个串建SAM,然后用后面的串去匹配,对于每一个串,保存最大值,对于不同的串,更新最小值。

SAM结点多两个值,ml表示多个串的最小值,nl表示当前串匹配的最大值。

  1 #include <iostream>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <stdio.h>
  5 
  6 using namespace std;
  7 const int N=250005;
  8 
  9 struct State
 10 {
 11     State *pre,*go[26];
 12     int step,nl,ml;
 13     void clear()
 14     {
 15         pre=0;
 16         step=0;
 17         memset(go,0,sizeof(go));
 18     }
 19 }*root,*last;
 20 
 21 State statePool[N*2],*b[2*N],*cur;
 22 
 23 void init()
 24 {
 25     cur=statePool;
 26     root=last=cur++;
 27     root->clear();
 28 }
 29 
 30 void Insert(int w)
 31 {
 32     State *p=last;
 33     State *np=cur++;
 34     np->clear();
 35     np->step=np->ml=p->step+1;
 36     while(p&&!p->go[w])
 37         p->go[w]=np,p=p->pre;
 38     if(p==0)
 39         np->pre=root;
 40     else
 41     {
 42         State *q=p->go[w];
 43         if(p->step+1==q->step)
 44             np->pre=q;
 45         else
 46         {
 47             State *nq=cur++;
 48             nq->clear();
 49             memcpy(nq->go,q->go,sizeof(q->go));
 50             nq->step=nq->ml=p->step+1;
 51             nq->pre=q->pre;
 52             q->pre=nq;
 53             np->pre=nq;
 54             while(p&&p->go[w]==q)
 55                 p->go[w]=nq, p=p->pre;
 56         }
 57     }
 58     last=np;
 59 }
 60 
 61 char str[N];
 62 int cnt[N];
 63 
 64 int main()
 65 {
 66     int n,m;
 67     scanf("%s",str);
 68     n=strlen(str);
 69     init();
 70     for(int i=0; i<n; i++)
 71         Insert(str[i]-'a');
 72     for(State *p=statePool; p!=cur; p++)
 73         cnt[p->step]++;
 74     for(int i=1; i<=n; i++)
 75         cnt[i]+=cnt[i-1];
 76     for(State *p=statePool; p!=cur; p++)
 77         b[--cnt[p->step]]=p;
 78     while(~scanf("%s",str))
 79     {
 80         int len=0;
 81         m=strlen(str);
 82         State *p=root;
 83         for(int i=0; i<m; i++)
 84         {
 85             int x=str[i]-'a';
 86             if(p->go[x])
 87             {
 88                 len++;
 89                 p=p->go[x];
 90             }
 91             else
 92             {
 93                 while(p&&!p->go[x]) p=p->pre;
 94                 if(!p) p=root,len=0;
 95                 else   len=p->step+1,p=p->go[x];
 96             }
 97             if(len>p->nl) p->nl=len;
 98         }
 99         int num=cur-statePool;
100         for(int i=num-1;i>=0;i--)
101         {
102             p=b[i];
103             if(p->ml>p->nl) p->ml=p->nl;
104             if(p->pre&&p->pre->nl<p->nl) p->pre->nl=p->nl;
105             p->nl=0;
106         }
107     }
108     int ans=0;
109     for(State *p=statePool;p!=cur;p++)
110         if(p->ml>ans) ans=p->ml;
111     printf("%d\n",ans);
112     return 0;
113 }

 

posted @ 2017-10-19 23:14  抓不住Jerry的Tom  阅读(180)  评论(0编辑  收藏  举报