POJ 2774 Long Long Message

POJ 2774 Long Long Message

链接

题意

  求两个串最长公共子串。

思路

  后缀数组:把两个串接在一起,求后缀数组和height,扫一遍即可。

  height是后缀数组排序后的排名相邻的两个串的公共前缀,那么两个串的最长公共子串一定是:两个排名相邻的串的公共前缀,(不能是不相邻的,不相邻的一定不会更优)。那么就是在height中扫一遍了。在判断一下是否来自两个串。

  

  后缀自动机:对A建立SAM,B在A上匹配。如果失配,跳到fa节点,fa节点保存的是当前点的一个后缀,在fa节点继续判断。其中每次更新ans。

 

代码

后缀数组

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 
 6 using namespace std;
 7 
 8 const int N = 200100; 
 9 char s[N];
10 int c[N],t1[N],t2[N],sa[N],height[N],rnk[N];
11 //sa[i]  排名为i的是谁 -下标 
12 //rnk[i] i的排名 -名次 
13 //height[i]  排名为i的后缀与排名为i-1的后缀的最长公共前缀长度 
14 int m = 130,n;
15 
16 void get_sa() {
17     int *x = t1,*y = t2,p,i;
18     for (i=0; i<m; ++i) c[i] = 0; 
19     for (i=0; i<n; ++i) x[i] = s[i],c[x[i]]++;
20     for (i=1; i<m; ++i) c[i] += c[i-1];
21     for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i;
22     for (int k=1; k<=n; k<<=1) {
23         p = 0;
24         for (i=n-k; i<n; ++i) y[p++] = i;
25         for (i=0; i<n; ++i) if (sa[i]>=k) y[p++] = sa[i]-k;
26         for (i=1; i<m; ++i) c[i] = 0;
27         for (i=0; i<n; ++i) c[ x[y[i]] ]++;
28         for (i=1; i<m; ++i) c[i] += c[i-1];
29         for (i=n-1; i>=0; --i) sa[--c[ x[y[i]] ]] = y[i];
30         swap(x,y);
31         p = 1;
32         x[sa[0]] = 0;
33         for (i=0; i<n; ++i) 
34             x[sa[i]] = (y[sa[i-1]]==y[sa[i]] && sa[i-1]+k<n && sa[i]+k<n &&    
35             y[sa[i-1]+k]==y[sa[i]+k]) ? p-1 : p++;
36         if (p >= n) break;
37         m = p;
38     }
39 }
40 void get_height() {
41     for (int i=0; i<n; ++i) rnk[sa[i]] = i;
42     int k = 0;
43     height[0] = 0;
44     for (int i=0; i<n; ++i) {
45         if (!rnk[i]) continue;
46         if (k) k--;
47         int j = sa[rnk[i]-1];
48         while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
49         height[rnk[i]] = k;
50     }
51 }
52 
53 int main() {
54     scanf("%s",s);
55     int n1 = strlen(s);
56     scanf("%s",s+n1);
57     int n2 = strlen(s+n1);
58     n = n1 + n2;
59     get_sa();
60     get_height();
61     int ans = 0;
62     for (int i=1; i<n; ++i) {
63         int mn = min(sa[i],sa[i-1]);
64         int mx = max(sa[i],sa[i-1]);
65         if (mn < n1 && mx >= n1) ans = max(ans,height[i]);
66     }
67     printf("%d",ans);
68     return 0;
69 }
View Code

 

后缀自动机 upd: 2018-07-19

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cctype>
 5 
 6 using namespace std;
 7 
 8 inline int read() {
 9     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
10     for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
11 }
12 
13 const int N = 100010;
14 
15 struct Suffix_Automaton{
16     int Index, Last, trans[N<<1][26], fa[N<<1], len[N<<1]; 
17     void extend(int c) {
18         int P = Last, NP = ++Index;
19         len[NP] = len[P] + 1;
20         for (; P&&!trans[P][c]; P=fa[P]) trans[P][c] = NP;
21         if (!P) fa[NP] = 1;
22         else {
23             int Q = trans[P][c];
24             if (len[P] + 1 == len[Q]) fa[NP] = Q;
25             else {
26                 int NQ = ++Index;
27                 fa[NQ] = fa[Q];
28                 len[NQ] = len[P] + 1;
29                 memcpy(trans[NQ], trans[Q], sizeof trans[Q]);
30                 fa[Q] = NQ;
31                 fa[NP] = NQ;
32                 for (; P&&trans[P][c]==Q; P=fa[P]) trans[P][c] = NQ;
33             }
34         }
35         Last = NP;
36     }    
37     void build(char *s) {
38         Index = 0;
39         Last = ++Index;
40         int n = strlen(s);
41         for (int i=0; i<n; ++i) extend(s[i]-'a');
42     }
43     int query(char *s) {
44         int n = strlen(s);
45         int Ans = 0,P = 1,now = 0;
46         for (int i=0; i<n; ++i) {
47             int c = s[i] - 'a';
48             if (trans[P][c]) P = trans[P][c], now++;
49             else {
50                 for (; P&&!trans[P][c]; P=fa[P]);
51                 if (!P) now = 0, P = 1;
52                 else now = len[P] + 1, P = trans[P][c];
53             }
54             Ans = max(Ans, now);
55         }
56         return Ans;
57     }
58 }SAM;
59 
60 char s[N];
61 
62 int main() {
63     scanf("%s",s);
64     SAM.build(s);
65     scanf("%s",s);
66     printf("%d",SAM.query(s));    
67     return 0;
68 }
View Code

 

posted @ 2018-05-04 07:55  MJT12044  阅读(161)  评论(0编辑  收藏  举报