POJ 3415 后缀数组+单调栈
链接:
http://poj.org/problem?id=3415
题意:
统计A和B长度不小于K的公共子串个数。
题解:
将A和B拼接后,利用单调栈累计分属两者的后缀对应的LCP-K+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 PII st[MAXN]; 74 ll contribution, top; 75 76 ll solve(int k, int n1, bool is_s1) { 77 ll ans = 0; 78 rep(i, 0, n) { 79 if (lcp[i] < k) { 80 top = contribution = 0; 81 continue; 82 } 83 int size = 0; 84 if (is_s1 && sa[i] < n1 || !is_s1 && sa[i] > n1) { 85 size++; 86 contribution += lcp[i] - k + 1; 87 } 88 while (top > 0 && st[top].first >= lcp[i]) { 89 contribution -= st[top].second*(st[top].first - lcp[i]); 90 size += st[top].second; 91 top--; 92 } 93 st[++top] = mp(lcp[i], size); 94 if (is_s1 && sa[i + 1] > n1 || !is_s1 && sa[i + 1] < n1) ans += contribution; 95 } 96 return ans; 97 } 98 99 int main() { 100 ios::sync_with_stdio(false), cin.tie(0); 101 int k; 102 while (cin >> k, k) { 103 string a, b; 104 cin >> a >> b; 105 int n1 = a.length(); 106 string s = a + '$' + b; 107 construct_sa(s, sa); 108 construct_lcp(s, sa, lcp); 109 cout << solve(k, n1, true) + solve(k, n1, false) << endl; 110 } 111 return 0; 112 }