链接:
http://codeforces.com/contest/427/problem/D
题意:
给你两个字符串s1,s2,找出最短的子串出现在s1和s2中有且只有一次
题解:
还是把s1和s2连起来,求lcp。首先要知道得是,最短长度一定是sa数组中一定是相连的,
这样就只需要遍历一遍lcp数组,更新ans就可以了
ans = min(ans, max(lcp[i - 1], lcp[i + 1]) + 1)
代码:
31 int n, k; 32 int Rank[MAXN], tmp[MAXN]; 33 int sa[MAXN], lcp[MAXN]; 34 35 bool compare_sa(int i, int j) { 36 if (Rank[i] != Rank[j]) return Rank[i] < Rank[j]; 37 else { 38 int ri = i + k <= n ? Rank[i + k] : -1; 39 int rj = j + k <= n ? Rank[j + k] : -1; 40 return ri < rj; 41 } 42 } 43 44 void construct_sa(string S, int *sa) { 45 n = S.length(); 46 for (int i = 0; i <= n; i++) { 47 sa[i] = i; 48 Rank[i] = i < n ? S[i] : -1; 49 } 50 for (k = 1; k <= n; k *= 2) { 51 sort(sa, sa + n + 1, compare_sa); 52 tmp[sa[0]] = 0; 53 for (int i = 1; i <= n; i++) 54 tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0); 55 for (int i = 0; i <= n; i++) Rank[i] = tmp[i]; 56 } 57 } 58 59 void construct_lcp(string S, int *sa, int *lcp) { 60 int n = S.length(); 61 for (int i = 0; i <= n; i++) Rank[sa[i]] = i; 62 int h = 0; 63 lcp[0] = 0; 64 for (int i = 0; i < n; i++) { 65 int j = sa[Rank[i] - 1]; 66 if (h > 0) h--; 67 for (; j + h < n && i + h < n; h++) 68 if (S[j + h] != S[i + h]) break; 69 lcp[Rank[i] - 1] = h; 70 } 71 } 72 73 int main() { 74 ios::sync_with_stdio(false), cin.tie(0); 75 string s1, s2; 76 cin >> s1 >> s2; 77 int n1 = s1.length(); 78 string s = s1 + "$" + s2; 79 construct_sa(s, sa); 80 construct_lcp(s, sa, lcp); 81 int ans = INF; 82 rep(i, 1, n + 1) if (lcp[i] > lcp[i - 1] && lcp[i] > lcp[i + 1]) 83 if (!((sa[i] > n1) ^ (sa[i + 1] < n1))) 84 ans = min(ans, max(lcp[i - 1], lcp[i + 1]) + 1); 85 if (ans == INF) ans = -1; 86 cout << ans << endl; 87 return 0; 88 }