后缀数组

Posted Milky Way

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了后缀数组相关的知识,希望对你有一定的参考价值。

bzoj 1031 [JSOI2007]字符加密Cipher

题意:给出一个字符串,将所有的循环排列按字典序从小到大排序,并输出最后一个字符

思路:将字符串复制一倍,求出 sa 数组,答案为 s[sa[i] + n - 1](sa[i] < n)。注意数组大小乘 2 !

技术分享图片
 1 #include <cstdio>
 2 #include <string>
 3 #include <cstring>
 4 
 5 const int N = 200010;
 6 int n, m = 130, x[N], y[N], sa[N], c[N];
 7 char s[N];
 8 
 9 void get_sa() {
10     for (int i = 0; i < m; ++ i) c[i] = 0;
11     for (int i = 0; i < n; ++ i) ++c[x[i] = s[i]];
12     for (int i = 1; i < m; ++ i) c[i] += c[i-1];
13     for (int i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i;
14     for (int k = 1; k <= n; k <<= 1) {
15         int p = 0;
16         for (int i = n - k; i < n; ++ i) y[p++] = i;
17         for (int i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
18         for (int i = 0; i < m; ++ i) c[i] = 0;
19         for (int i = 0; i < n; ++ i) ++c[x[y[i]]];
20         for (int i = 1; i < m; ++ i) c[i] += c[i-1];
21         for (int i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i];
22         for (int i = 0; i < n; ++ i) x[i] ^= y[i], y[i] ^= x[i], x[i] ^= y[i];
23         p = 1, x[sa[0]] = 0;
24         for (int i = 1; i < n; ++ i)
25             x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++;
26         if (p >= n) break;
27         m = p;
28     }
29 }
30 
31 int main() {
32     scanf("%s", s), n = strlen(s);
33     for (int i = 0; i < n; ++ i) s[i+n] = s[i];
34     int t = n; n *= 2, get_sa();
35     for (int i = 0; i < n; ++ i)
36         if (sa[i] < t) printf("%c", s[sa[i]+t-1]);
37     puts(""); return 0;
38 }
View Code

bzoj 4698 Sdoi2008 Sandy的卡片

题意:求 n 个字符串的最长公共子串

思路:将 n 个字符串拼接成一个串,中间用未出现过且不同的字母分隔(字符ID不限于128),求出 height 后二分。

技术分享图片
  1 #include <cstdio>
  2 #include <string>
  3 #include <cstring>
  4 
  5 const int N = 102005, INF = 0x3f3f3f3f;
  6 
  7 int n, m, t;
  8 int a[1005][1005], sa[N], c[N], x[N], y[N], s[N];
  9 int rank[N], height[N], vis[N], sta[N], top, id[N];
 10 
 11 int read() {
 12     int x = 0, f = 1;
 13     char c = getchar();
 14     while (!isdigit(c)) {
 15         if (c == -) f = -1;
 16         c = getchar();
 17     }
 18     while (isdigit(c)) {
 19         x = (x << 3) + (x << 1) + (c ^ 48);
 20         c = getchar();
 21     }
 22     return x * f;
 23 }
 24 
 25 int min(int x, int y) { if (x <= y) return x; return y; }
 26 int max(int x, int y) { if (x >= y) return x; return y; }
 27 
 28 void getSa() {
 29     for (int i = 0; i < m; ++ i) c[i] = 0;
 30     for (int i = 0; i < n; ++ i) ++c[x[i] = s[i]];
 31     for (int i = 1; i < m; ++ i) c[i] += c[i-1];
 32     for (int i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i;
 33     
 34     for (int k = 1; k <= n; k <<= 1) {
 35         int p = 0;
 36         for (int i = n - k; i < n; ++ i) y[p++] = i;
 37         for (int i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
 38         
 39         for (int i = 0; i < m; ++ i) c[i] = 0;
 40         for (int i = 0; i < n; ++ i) ++c[x[y[i]]];
 41         for (int i = 1; i < m; ++ i) c[i] += c[i-1];
 42         for (int i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i];
 43         
 44         for (int i = 0; i < n; ++ i) x[i] ^= y[i], y[i] ^= x[i], x[i] ^= y[i];
 45         p = 1, x[sa[0]] = 0;
 46         for (int i = 1; i < n; ++ i)
 47             x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k] ? p-1 : p++;
 48         if (p >= n) break;
 49         m = p;
 50     }
 51 }
 52 
 53 void getHeight() {
 54     int k = 0;
 55     for (int i = 0; i < n; ++ i) rank[sa[i]] = i;
 56     for (int i = 0; i < n; ++ i) {
 57         if (!rank[i]) continue;
 58         if (k) --k;
 59         int j = sa[rank[i]-1];
 60         while (i+k < n && j+k < n && s[i+k] == s[j+k]) ++k;
 61         height[rank[i]] = k;
 62     }
 63 }
 64 
 65 bool check(int x) {
 66     while (top) vis[sta[top--]] = 0;
 67     for (int i = 0; i < n; ++ i) {
 68         if (height[i] < x) while(top) vis[sta[top--]] = 0;
 69         if (!vis[id[sa[i]]]) {
 70             vis[id[sa[i]]] = 1;
 71             sta[++top] = id[sa[i]];
 72             if (top == t) return true;
 73         }
 74     }
 75     return false;
 76 }
 77 
 78 int main() {
 79     freopen("card.in", "r", stdin);
 80     freopen("card.out", "w", stdout);
 81     
 82     t = read(); int l = 0, r = INF, minn = INF, maxn = 0;
 83     for (int i = 1; i <= t; ++ i) {
 84         a[i][0] = read(), a[i][1] = read();
 85         r = min(r, a[i][0] - 1);
 86         for (int j = 2; j <= a[i][0]; ++ j) {
 87             a[i][j] = read();
 88             minn = min(minn, a[i][j] - a[i][j-1]);
 89             maxn = max(maxn, a[i][j] - a[i][j-1]);
 90         }
 91     }
 92     for (int i = 1; i <= t; ++ i) {
 93         for (int j = 2; j <= a[i][0]; ++ j)
 94             id[n] = i, s[n++] = a[i][j] - a[i][j-1] - minn;
 95         s[n++] = ++maxn - minn;
 96     }
 97     for (int i = 0; i < n; ++ i) m = max(m, s[i] + 1);
 98     getSa(), getHeight();
 99     while (l < r) {
100         int mid = l + ((r - l + 1) >> 1);
101         if (check(mid)) l = mid; else r = mid - 1;
102     }
103     printf("%d\n", l + 1); return 0;
104 }
View Code

 

以上是关于后缀数组的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段—— 数组的响应式方法

VSCode自定义代码片段10—— 数组的响应式方法

Sublime Text3自定义代码片段

后缀数组代码详解

●后缀数组○十三个例题

初学后缀数组记录(然而并不是很会。。&&很水。。)