J - Long Long Message (最长公共子串)
题目链接:https://cn.vjudge.net/contest/283743#problem/J
题目大意:给你两个字符串,问你两个字符串的最长的公共子串。
具体思路:把两个字符串合在一起,然后求后缀数组,按照排名之后的字符串,如果两个相邻的字符串的sa[i]和sa[i-1]分别属于两个字符串,那么这个就是题目允许的值之一,然后再从这些值里面找一个最大的输出就可以了。
AC代码:
1 #include<iostream> 2 #include<stack> 3 #include<cstring> 4 #include<iomanip> 5 #include<stdio.h> 6 #include<algorithm> 7 #include<cmath> 8 using namespace std; 9 # define ll long long 10 # define inf 0x3f3f3f3f 11 const int maxn = 5e5+100; 12 int cntA[maxn], cntB[maxn], sa[maxn], tsa[maxn], A[maxn], B[maxn], height[maxn]; 13 int Rank[maxn]; 14 char ch[maxn]; 15 char str1[maxn]; 16 int sto[maxn]; 17 ll n; 18 //sa[i]代表第i小的后缀位置,Rank[i]代表第i位置的后缀,排名第几小 19 // height[i]代表排名第i个字符串和第i-1个字符串的相同前缀有多少个 20 void cal() 21 { 22 for(int i = 0; i < 256; i++) 23 cntA[i] = 0; 24 for(int i = 1; i <= n; i++) 25 { 26 cntA[ch[i-1]]++; 27 } 28 for(int i = 1; i < 256; i++) 29 cntA[i] += cntA[i-1]; 30 for(int i = n; i; i--) 31 sa[cntA[ch[i-1]]--] = i; 32 Rank[sa[1]] = 1; 33 for(int i = 2; i <= n; i++) 34 { 35 Rank[sa[i]] = Rank[sa[i-1]]; 36 if(ch[sa[i]-1] != ch[sa[i-1]-1]) 37 Rank[sa[i]]++; 38 } 39 for(int l = 1; Rank[sa[n]] < n; l <<= 1) 40 { 41 memset(cntA, 0, sizeof(cntA)); 42 memset(cntB, 0, sizeof(cntB)); 43 for(int i = 1; i <= n; i++) 44 { 45 cntA[A[i] = Rank[i]]++; 46 cntB[B[i] = (i+l <= n)?Rank[i+l]:0]++; 47 } 48 for(int i = 1; i <= n; i++) 49 cntB[i] += cntB[i-1]; 50 for(int i = n; i; i--) 51 tsa[cntB[B[i]]--] = i; 52 for(int i = 1; i <= n; i++) 53 cntA[i] += cntA[i-1]; 54 for(int i = n; i; i--) 55 sa[cntA[A[tsa[i]]]--] = tsa[i]; 56 Rank[sa[1]]=1; 57 for(int i = 2; i <= n; i++) 58 { 59 Rank[sa[i]] = Rank[sa[i-1]]; 60 if(A[sa[i]] != A[sa[i-1]] || B[sa[i]] != B[sa[i-1]]) 61 Rank[sa[i]]++; 62 } 63 } 64 for(int i = 1, j = 0; i <= n; i++) 65 { 66 if(j) 67 j--; 68 while(ch[i+j-1] == ch[sa[Rank[i]-1] + j - 1]) 69 j++; 70 height[Rank[i]] = j; 71 } 72 } 73 int main() 74 { 75 scanf("%s",str1); 76 int len1=strlen(str1); 77 for(int i=0; i<len1; i++) 78 { 79 ch[i]=str1[i]; 80 } 81 scanf("%s",str1); 82 int len2=strlen(str1); 83 for(int i=len1; i<len1+len2; i++) 84 { 85 ch[i]=str1[i-len1]; 86 } 87 n=len1+len2; 88 cal(); 89 int maxx=0; 90 for(int i=2; i<=len1+len2; i++) 91 { 92 if(height[i]>maxx) 93 { 94 if(sa[i]>=1&&sa[i]<=len1&&sa[i-1]>=(1+len1)&&sa[i-1]<=len1+len2) 95 maxx=height[i]; 96 if(sa[i-1]>=1&&sa[i-1]<=len1&&sa[i]>=(1+len1)&&sa[i]<=len1+len2) 97 maxx=height[i]; 98 } 99 } 100 printf("%d\n",maxx); 101 return 0; 102 }