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 }
后缀自动机 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 }