后缀数组初步

2015年11月18日

  uoj模板题:

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (register int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (register int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 
11 using namespace std;
12 
13 typedef long long i64;
14 typedef pair<int, int> pii;
15 const int inf = ~0U >> 1;
16 const i64 INF = ~0ULL >> 1;
17 //********************************
18 
19 const int maxn = 100005;
20 
21 char s[maxn];
22 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
23 void build_sa(int m) {
24     int *x = t, *y = t2;
25     REP(i, 0, m) c[i] = 0;
26     REP(i, 0, n) c[x[i] = s[i]]++;
27     REP(i, 1, m) c[i] += c[i - 1];
28     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
29     for (int k = 1; k <= n; k <<= 1) {
30         int p = 0;
31         REP(i, n - k, n) y[p++] = i;
32         REP(i, 0 , n) if (sa[i] >= k) y[p++] = sa[i] - k;
33 
34         REP(i, 0, m) c[i] = 0;
35         REP(i, 0, n) c[x[y[i]]]++;
36         REP(i, 1, m) c[i] += c[i - 1];
37         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
38 
39         swap(x, y);
40         p = 1; x[sa[0]] = 0;
41         REP(i, 1, n)
42             x[sa[i]] = y[sa[i - 1]]==y[sa[i]] && y[sa[i - 1] + k]==y[sa[i] + k] ? p - 1 : p++;
43         if (p >= n) break;
44         m = p;
45     }
46 }
47 
48 int rnk[maxn], height[maxn];
49 void getHeight() {
50     REP(i, 0, n) rnk[sa[i]] = i;
51     int k(0);
52     REP(i, 0, n) {
53         if (k) k--;
54         int j = sa[rnk[i] - 1];
55         while (s[i + k] == s[j + k]) k++;
56         height[rnk[i]] = k;
57     }
58 }
59 
60 int main() {
61     scanf("%s", s);
62     n = strlen(s) + 1;
63     build_sa('z' + 1);
64     REP(i, 1, n) printf("%d ", sa[i] + 1);
65     puts("");
66     getHeight();
67     REP(i, 2, n) printf("%d ", height[i]);
68     return 0;
69 }
View Code

2015年11月20日

  poj1743 <最大不重合公共子序列长度>

    给出一个数列,差分之,求出最长差分相同的序列。

    首先后缀a和后缀b的LCP为height[sa[a] + 1] - height[sa[b]]的最小值,假设sa[a] < sa[b];

    那么若不考虑重合,在二分答案的同时,将height数组按大于等于二分值和小于二分值分段,比如(1, 2, 3, 4, 1, 2) 用2来二分 则划分为(1, (2, 3, 4), (1), (2)); 

    再考虑重合,符合答案的情况则一定在大于二分值的每段中,只需找到每一个大于二分值的段中的最大sa和最小sa,然后Max - Min > mid 即可,>是因为差分后不能重合,若没有差分,则用>=

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define rep(i, a, b) for (int i = a; i <= b; i++)
  5 #define REP(i, a, b) for (int i = a; i < b; i++)
  6 #define drep(i, a, b) for (int i = a; i >= b; i--)
  7 #define pb push_back
  8 #define mp make_pair
  9 #define clr(x) memset(x, 0, sizeof(x))
 10 #define travel(x) for (int i = G[x]; i; i = e[i].nx)
 11 #define xx first
 12 #define yy second
 13 
 14 using namespace std;
 15 
 16 typedef long long i64;
 17 typedef pair<int, int> pii;
 18 const int inf = ~0U >> 1;
 19 const i64 INF = ~0ULL >> 1;
 20 //***************************
 21 
 22 const int maxn = 20005;
 23 
 24 int s[maxn];
 25 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 26 void build_sa(int m) {
 27     int *x = t, *y = t2;
 28     REP(i, 0, m) c[i] = 0;
 29     REP(i, 0, n) c[x[i] = s[i]]++;
 30     REP(i, 1, m) c[i] += c[i - 1];
 31     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 32 
 33     for (int k = 1; k <= n; k <<= 1) {
 34         int p = 0;
 35         REP(i, n - k, n) y[p++] = i;
 36         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 37 
 38         REP(i, 0, m) c[i] = 0;
 39         REP(i, 0, n) c[x[y[i]]]++;
 40         REP(i, 1, m) c[i] += c[i - 1];
 41         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 42 
 43         swap(x, y);
 44         p = 1, x[sa[0]] = 0;
 45         REP(i, 1, n)
 46             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
 47         if (p >= n) break;
 48         m = p;
 49     }
 50 }
 51 
 52 int rnk[maxn], height[maxn];
 53 void buildHeight() {
 54     int k(0);
 55     REP(i, 0, n) rnk[sa[i]] = i;
 56     REP(i, 0, n) {
 57         if (k) k--;
 58         if (rnk[i] == 0) continue;
 59         int j = sa[rnk[i] - 1];
 60         while (s[i + k] == s[j + k]) k++;
 61         height[rnk[i]] = k;
 62     }
 63 }
 64 
 65 bool judge(int key) {
 66     int Min = 0x3f3f3f3f, Max = -0x3f3f3f3f;
 67     REP(i, 1, n) {
 68         if (height[i] >= key) {
 69             Min = min(Min, min(sa[i - 1], sa[i]));
 70             Max = max(Max, max(sa[i - 1], sa[i]));
 71         }
 72         else {
 73             if (Max - Min > key) return true;
 74             Min = 0x3f3f3f3f, Max = -0x3f3f3f3f;
 75         }
 76     }
 77     if (Max - Min > key) return true;
 78     else return false;
 79 }
 80 
 81 int a[maxn];
 82 int main() {
 83     while (scanf("%d", &n) && n) {
 84         REP(i, 0, n) scanf("%d", &a[i]);
 85         if (n < 10) { puts("0"); continue; }
 86         REP(i, 0, n - 1) s[i] = a[i + 1] - a[i] + 100;
 87         s[n - 1] = 0;
 88         build_sa(200), buildHeight();
 89         
 90         int low = 0, high = maxn - 1;
 91         while (low < high - 1) {
 92             int mid = low + high >> 1;
 93             if (judge(mid)) low = mid;
 94             else  high = mid;
 95         }
 96         if (low + 1 < 5) puts("0");
 97         else printf("%d
", low + 1);
 98     }
 99     return 0;
100 }
View Code

  poj3261 <最大可重复公共子序列长度>

    和上一题一样。不要忘记判judge()的最后一个!!!

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define rep(i, a, b) for (int i = a; i <= b; i++)
  5 #define drep(i, a, b) for (int i = a; i >= b; i--)
  6 #define REP(i, a, b) for (int i = a; i < b; i++)
  7 #define mp make_pair
  8 #define pb push_back
  9 #define clr(x) memset(x, 0, sizeof(x))
 10 #define xx first
 11 #define yy second
 12 
 13 using namespace std;
 14 
 15 typedef long long i64;
 16 typedef pair<int, int> pii;
 17 const int inf = ~0U >> 1;
 18 const i64 INF = ~0ULL >> 1;
 19 //*****************************
 20 
 21 const int maxn = 20005;
 22 int hsh[maxn], cd;
 23 int s[maxn], sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 24 void build_sa(int m) {
 25     int *x = t, *y = t2;
 26     REP(i, 0, m) c[i] = 0;
 27     REP(i, 0, n) c[x[i] = s[i]]++;
 28     REP(i, 1, m) c[i] += c[i - 1];
 29     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 30 
 31     for (int k = 1; k <= n; k <<= 1) {
 32         int p = 0;
 33         REP(i, n - k, n) y[p++] = i;
 34         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 35 
 36         REP(i, 0, m) c[i] = 0;
 37         REP(i, 0, n) c[x[y[i]]]++;
 38         REP(i, 1, m) c[i] += c[i - 1];
 39         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 40 
 41         swap(x, y);
 42         p = 1; x[sa[0]] = 0;
 43         REP(i, 1, n)
 44             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
 45         if (p >= n) break;
 46         m = p;
 47     }
 48 }
 49 
 50 int rnk[maxn], height[maxn];
 51 void build_height() {
 52     REP(i, 0, n) rnk[sa[i]] = i;
 53     int k(0);
 54     REP(i,  0, n - 1) {
 55         if (k) k--;
 56         int j = sa[rnk[i] - 1];
 57         while (s[i + k] == s[j + k]) k++;
 58         height[rnk[i]] = k;
 59     }
 60 }
 61 
 62 bool judge(int key, int k) {
 63     int cnt(0);
 64     REP(i, 2, n) {
 65         if (height[i] >= key) cnt++;
 66         else {
 67             if (cnt + 1 >= k) return true;
 68             cnt = 0;
 69         }
 70     }
 71     if (cnt + 1 >= k) return true;
 72     else return false;
 73 }
 74 
 75 int read() {
 76     int l = 1, ret(0);
 77     char ch = getchar();
 78     while (ch < '0' || ch > '9') {if (ch == '-') l = -1; ch = getchar(); }
 79     while (ch >= '0' && ch <= '9') { ret = (ret << 1) + (ret << 3) + ch - '0'; ch = getchar(); }
 80     return l * ret;
 81 }
 82 int a[maxn];
 83 int main() {
 84     int k;
 85     scanf("%d%d", &n, &k);
 86     n++;
 87     rep(i, 1, n) scanf("%d", &a[i]), hsh[cd++] = a[i];
 88     sort(hsh, hsh + n); cd = unique(hsh, hsh + cd) - hsh;
 89     REP(i, 0, n) s[i] = lower_bound(hsh, hsh + cd, a[i + 1]) - hsh;
 90     build_sa(cd); build_height();
 91     
 92     int low = 0, high = maxn;
 93     while (low < high - 1) {
 94         int mid = low + high >> 1;
 95         if (judge(mid, k)) low = mid;
 96         else high = mid;
 97     }
 98     printf("%d
", low);
 99     return 0;
100 }
View Code

  spoj694 <不同子序列个数>

    首先后缀数组,考虑按sa的顺序依次加入考虑,每加入一个,则以它开头的子串会增加len - sa[i]个,考虑这些被加入的字符串的重复情况,因为height往上递减,所以用它和以前的重复情况不如考虑它和它 - 1的重复情况,即减去height[i];

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define rep(i, a, b) for (int i = a; i <= b; i++)
 5 #define drep(i, a, b) for (int i = a; i >= b; i--)
 6 #define REP(i, a, b) for (int i = a; i < b; i++)
 7 #define mp make_pair
 8 #define pb push_back
 9 #define clr(x) memset(x, 0, sizeof(x))
10 #define xx first
11 #define yy second
12 
13 using namespace std;
14 
15 typedef long long i64;
16 typedef pair<int, int> pii;
17 const int inf = ~0U >> 1;
18 const i64 INF = ~0ULL >> 1;
19 //*****************************
20 
21 const int maxn = 1005;
22 char s[maxn];
23 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
24 void build_sa(int m) {
25     int *x = t, *y = t2;
26     REP(i, 0, m) c[i] = 0;
27     REP(i, 0, n) c[x[i] = s[i]]++;
28     REP(i, 1, m) c[i] += c[i - 1];
29     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
30 
31     for (int k = 1; k <= n; k <<= 1) {
32         int p = 0;
33         REP(i, n - k, n) y[p++] = i;
34         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
35 
36         REP(i, 0, m) c[i] = 0;
37         REP(i, 0, n) c[x[y[i]]]++;
38         REP(i, 1, m) c[i] += c[i - 1];
39         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
40 
41         swap(x, y);
42         p = 1; x[sa[0]] = 0;
43         REP(i, 1, n)
44             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
45         if (p >= n) break;
46         m = p;
47     }
48 }
49 
50 int rnk[maxn], height[maxn];
51 void build_height() {
52     int k(0);
53     REP(i, 0, n) rnk[sa[i]] = i;
54     REP(i, 0, n - 1) {
55         if (k) k--;
56         int j = sa[rnk[i] - 1];
57         while (s[i + k] == s[j + k]) k++;
58         height[rnk[i]] = k;
59     }
60 }
61 
62 int main() {
63     int T;
64     scanf("%d", &T);
65     while (T--) {
66         scanf("%s", s);
67         n = strlen(s) + 1;
68         build_sa('z' + 1); build_height();
69         int ans(0);
70         REP(i, 1, n) {
71             ans += n - sa[i] - 1;
72             ans -= height[i];
73         }
74         printf("%d
", ans);
75     }
76     return 0;
77 }
View Code

2015年11月22日

  ural1297 <最长回文子串>

    将原字符串翻转后接在一开始的字符串后面,用rmq查询两个字符串的LCP,依次枚举每一个点即可。记住:n总比最后一个下标大2.

  1 #include <bits/stdc++.h>
  2 #define rep(i, a, b) for (int i = a; i <= b; i++)
  3 #define drep(i, a, b) for (int i = a; i >= b; i--)
  4 #define REP(i, a, b) for (int i = a; i < b; i++)
  5 #define pb push_back
  6 #define mp make_pair
  7 #define clr(x) memset(x, 0, sizeof(x))
  8 #define xx first
  9 #define yy second
 10 using namespace std;
 11 typedef long long i64;
 12 typedef pair<int, int> pii;
 13 const int inf = ~0U>>1;
 14 const i64 INF = ~0ULL>>1;
 15 //***************************
 16 
 17 const int maxn = 600005;
 18 char s[maxn];
 19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 20 void build_sa(int m) {
 21     int *x = t, *y = t2;
 22     REP(i, 0, m) c[i] = 0;
 23     REP(i, 0, n) c[x[i] = s[i]]++;
 24     REP(i, 1, m) c[i] += c[i - 1];
 25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 26 
 27     for (int k = 1; k <= n; k <<= 1) {
 28         int p = 0;
 29         REP(i, n - k, n) y[p++] = i;
 30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 31 
 32         REP(i, 0, m) c[i] = 0;
 33         REP(i, 0, n) c[x[y[i]]]++;
 34         REP(i, 1, m) c[i] += c[i - 1];
 35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 36 
 37         swap(x, y);
 38         p = 1, x[sa[0]] = 0;
 39         REP(i, 1, n)
 40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
 41         if (p >= n) break;
 42         m = p;
 43     }
 44 }
 45 
 46 int rnk[maxn], height[maxn];
 47 void build_height() {
 48     REP(i, 0, n) rnk[sa[i]] = i;
 49     int k(0);
 50     REP(i, 0, n - 1) {
 51         if (k) k--;
 52         int j = sa[rnk[i] - 1];
 53         while (s[i + k] == s[j + k]) k++;
 54         height[rnk[i]] = k;
 55     }
 56 }
 57 
 58 char str[maxn];
 59 
 60 int Min[maxn][32], Log[maxn];
 61 void build_st(int lim) {
 62     Log[1] = 0;
 63     rep(i, 2, lim) {
 64         Log[i] = Log[i - 1];
 65         if (1 << Log[i] + 1 == i) Log[i]++;
 66     }
 67     drep(i, lim - 1, 1) {
 68         Min[i][0] = height[i];
 69         for (int j = 1; i + (1 << j) - 1 < lim; j++) {
 70             Min[i][j] = min(Min[i][j - 1], Min[i + (1 << j - 1)][j - 1]);
 71         }
 72     }
 73 }
 74 int query(int l, int r) {
 75     int len = r - l + 1, k = Log[len];
 76     return min(Min[l][k], Min[r - (1 << k) + 1][k]);
 77 }
 78 
 79 int main() {
 80     scanf("%s", str);
 81     n = strlen(str);
 82     memcpy(s, str, sizeof(str));
 83     s[n] = '$';
 84     rep(i, 1, n) s[n + i] = s[n - i];
 85     n++, n <<= 1;
 86     build_sa('z' + 1); build_height();
 87     build_st(n);
 88     int ans = -1, strt;
 89     for (int i = 0; str[i]; i++) {
 90         int j = n - 2 - i;
 91         int tmp = query(min(rnk[i], rnk[j]) + 1, max(rnk[i], rnk[j]));
 92         int len = (tmp << 1) - 1;
 93         if (len > ans) ans = len, strt = i - tmp + 1;
 94         j++; tmp = query(min(rnk[i], rnk[j]) + 1, max(rnk[i], rnk[j]));
 95         len = tmp << 1;
 96         if (len > ans) ans = len, strt = i - tmp;
 97     }
 98     while (ans--) putchar(s[strt++]);
 99     return 0;
100 }
View Code

  APIO2014 Palindromes <回文子串长度 * 这个子串出现次数的最大值> TLE

    这个题应该Manacher+后缀数组,Manachar后面学,,我用后缀数组统计超时了。。。

  1 #include <bits/stdc++.h>
  2 #define rep(i, a, b) for (int i = a; i <= b; i++)
  3 #define drep(i, a, b) for (int i = a; i >= b; i--)
  4 #define REP(i, a, b) for (int i = a; i < b; i++)
  5 #define pb push_back
  6 #define mp make_pair
  7 #define clr(x) memset(x, 0, sizeof(x))
  8 #define xx first
  9 #define yy second
 10 using namespace std;
 11 typedef long long i64;
 12 typedef pair<int, int> pii;
 13 const int inf = ~0U>>1;
 14 const i64 INF = ~0ULL>>1;
 15 //***************************
 16 
 17 const int maxn = 600005;
 18 char s[maxn];
 19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 20 void build_sa(int m) {
 21     int *x = t, *y = t2;
 22     REP(i, 0, m) c[i] = 0;
 23     REP(i, 0, n) c[x[i] = s[i]]++;
 24     REP(i, 1, m) c[i] += c[i - 1];
 25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 26 
 27     for (int k = 1; k <= n; k <<= 1) {
 28         int p = 0;
 29         REP(i, n - k, n) y[p++] = i;
 30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 31 
 32         REP(i, 0, m) c[i] = 0;
 33         REP(i, 0, n) c[x[y[i]]]++;
 34         REP(i, 1, m) c[i] += c[i - 1];
 35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 36 
 37         swap(x, y);
 38         p = 1, x[sa[0]] = 0;
 39         REP(i, 1, n)
 40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
 41         if (p >= n) break;
 42         m = p;
 43     }
 44 }
 45 
 46 int rnk[maxn], height[maxn];
 47 void build_height() {
 48     REP(i, 0, n) rnk[sa[i]] = i;
 49     int k(0);
 50     REP(i, 0, n - 1) {
 51         if (k) k--;
 52         int j = sa[rnk[i] - 1];
 53         while (s[i + k] == s[j + k]) k++;
 54         height[rnk[i]] = k;
 55     }
 56 }
 57 
 58 char str[maxn];
 59 
 60 int Min[maxn][32], Log[maxn];
 61 void build_st(int lim) {
 62     Log[1] = 0;
 63     rep(i, 2, lim) {
 64         Log[i] = Log[i - 1];
 65         if (1 << Log[i] + 1 == i) Log[i]++;
 66     }
 67     drep(i, lim - 1, 1) {
 68         Min[i][0] = height[i];
 69         for (int j = 1; i + (1 << j) - 1 < lim; j++) {
 70             Min[i][j] = min(Min[i][j - 1], Min[i + (1 << j - 1)][j - 1]);
 71         }
 72     }
 73 }
 74 int query(int l, int r) {
 75     int len = r - l + 1, k = Log[len];
 76     return min(Min[l][k], Min[r - (1 << k) + 1][k]);
 77 }
 78 
 79 int search_above(int low, int high, int len, int pos) {
 80     while (low < high - 1) {
 81         int mid = low + high >> 1;
 82         if (query(mid + 1, pos) >= len) high = mid;
 83         else  low = mid;
 84     }
 85     return high;
 86 }
 87 
 88 int search_behind(int low, int high, int len, int pos) {
 89     while (low < high - 1) {
 90         int mid = low + high >> 1;
 91         if (query(pos + 1, mid) >= len) low = mid;
 92         else high = mid;
 93     }
 94     return low;
 95 }
 96 
 97 int ans = -1;
 98 void solve(int st, int len) {
 99     while (1) {
100         int pos = rnk[st];
101         int pos1 = search_above(0, pos, len, pos);
102         int pos2 = search_behind(pos, n, len, pos);
103         ans = max(ans, (pos2 - pos1 + 1) * len >> 1);
104         len -= 2;
105         st += 1;
106         if (len <= 0) break;
107     }
108 }
109 
110 int main() {
111     scanf("%s", str);
112     n = strlen(str);
113     memcpy(s, str, sizeof(str));
114     s[n] = '$';
115     rep(i, 1, n) s[n + i] = s[n - i];
116     n++, n <<= 1;
117     build_sa('z' + 1); build_height();
118     build_st(n);
119     for (int i = 0; str[i]; i++) {
120         int j = n - 2 - i;
121         int tmp = query(min(rnk[i], rnk[j]) + 1, max(rnk[i], rnk[j]));
122         int len = (tmp << 1) - 1;
123         solve(i - tmp + 1, len);
124         j++; tmp = query(min(rnk[i], rnk[j]) + 1, max(rnk[i], rnk[j]));
125         len = tmp << 1;
126         solve(i - tmp, len);
127     }
128     printf("%d
", ans);
129     return 0;
130 }
View Code

  poj2406 <连续重复子串> TLE

    倍增后缀数组TLE...原来是KMP做的。

    暴力枚举长度k,然后查询rnk[n - k]和rnk[0]的LCP,若LCP >= n - k则当前k可行。只需预先处理出所有后缀和rnk[0]的最小值即可。

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = ~0U>>1;
14 const i64 INF = ~0ULL>>1;
15 //***************************
16 
17 const int maxn = 1000005;
18 char s[maxn];
19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
20 void build_sa(int m) {
21     int *x = t, *y = t2;
22     REP(i, 0, m) c[i] = 0;
23     REP(i, 0, n) c[x[i] = s[i]]++;
24     REP(i, 1, m) c[i] += c[i - 1];
25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
26 
27     for (int k = 1; k <= n; k++) {
28         int p(0);
29         REP(i, n - k, n) y[p++] = i;
30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
31 
32         REP(i, 0, m) c[i] = 0;
33         REP(i, 0, n) c[x[y[i]]]++;
34         REP(i, 1, m) c[i] += c[i - 1];
35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
36 
37         swap(x, y);
38         p = 1, x[sa[0]] = 0;
39         REP(i, 1, n)
40             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
41         if (p >= n) break;
42         m = p;
43     }
44 }
45 
46 int rnk[maxn], height[maxn];
47 void build_height() {
48     REP(i, 0, n) rnk[sa[i]] = i;
49     int k(0);
50     REP(i, 0, n - 1) {
51         if (k) k--;
52         int j = sa[rnk[i] - 1];
53         while (s[i + k] == s[j + k]) k++;
54         height[rnk[i]] = k;
55     }
56 }
57 
58 int Min[maxn];
59 int main() {
60     while (1) {
61         scanf("%s", s);
62         if (s[0] == '.') break;
63         n = strlen(s) + 1;
64         build_sa('z' + 1), build_height();
65 
66         int pos = rnk[0];
67         Min[pos - 1] = height[pos], Min[pos + 1] = height[pos + 1];
68         drep(i, pos - 2, 0) Min[i] = min(Min[i + 1], height[i + 1]);
69         REP(i, pos + 2, n) Min[i] = min(Min[i - 1], height[i]);
70 
71         int len = strlen(s);
72         rep(i, 1, len) {
73             if (len % i) continue;
74             if (Min[rnk[i]] >= len - i) {
75                 printf("%d
", len / i);
76                 break;
77             }
78         }
79     }
80     return 0;
81 }
View Code

  poj3693 <重复次数最多的连续重复子串>

    先考虑重复两遍的情况,这个子串S中的[0], [L], [L * 2],[L * 3]...中至少有相邻两个被包含,考察 S[i * l] 和 S[(i + 1) * l] 的LCP,设其值为k,若 k%l有值,则可认为LCP多匹配了k%l,也可认为是少匹配了 l - k%l,向前枚举直到不符合.

  1 #include <bits/stdc++.h>
  2 #define rep(i, a, b) for (int i = a; i <= b; i++)
  3 #define drep(i, a, b) for (int i = a; i >= b; i--)
  4 #define REP(i, a, b) for (int i = a; i < b; i++)
  5 #define pb push_back
  6 #define mp make_pair
  7 #define clr(x) memset(x, 0, sizeof(x))
  8 #define xx first
  9 #define yy second
 10 using namespace std;
 11 typedef long long i64;
 12 typedef pair<int, int> pii;
 13 const int inf = ~0U>>1;
 14 const i64 INF = ~0ULL>>1;
 15 //***************************
 16 
 17 const int maxn = 200005;
 18 char s[maxn];
 19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 20 void build_sa(int m) {
 21     int *x = t, *y = t2;
 22     REP(i, 0, m) c[i] = 0;
 23     REP(i, 0, n) c[x[i] = s[i]]++;
 24     REP(i, 1, m) c[i] += c[i - 1];
 25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 26 
 27     for (int k = 1; k <= n; k <<= 1) {
 28         int p(0);
 29         REP(i, n - k, n) y[p++] = i;
 30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 31 
 32         REP(i, 0, m) c[i] = 0;
 33         REP(i, 0, n) c[x[y[i]]]++;
 34         REP(i, 1, m) c[i] += c[i - 1];
 35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 36 
 37         swap(x, y);
 38         p = 1, x[sa[0]] = 0;
 39         REP(i, 1, n)
 40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
 41         if (p >= n) break;
 42         m = p;
 43     }
 44 }
 45 
 46 int rnk[maxn], height[maxn];
 47 void build_height() {
 48     REP(i, 0, n) rnk[sa[i]] = i;
 49     int k(0);
 50     REP(i, 0, n - 1) {
 51         if (k) k--;
 52         int j = sa[rnk[i] - 1];
 53         while (s[i + k] == s[j + k]) k++;
 54         height[rnk[i]] = k;
 55     }
 56 }
 57 
 58 int Min[maxn][32], Log[maxn];
 59 void build_st(int lim) {
 60     Log[1] = 0;
 61     rep(i, 2, lim) {
 62         Log[i] = Log[i - 1];
 63         if (1 << Log[i] + 1 == i) Log[i]++;
 64     }
 65     drep(i, lim, 1) {
 66         Min[i][0] = height[i];
 67         for (int j = 1; i + (1 << j) - 1 <= lim; j++)
 68             Min[i][j] = min(Min[i][j - 1], Min[i + (1 << j - 1)][j - 1]);
 69     }
 70 }
 71 int query(int l, int r) {
 72     int len = r - l + 1, k = Log[len];
 73     return min(Min[l][k], Min[r - (1 << k) + 1][k]);
 74 }
 75 
 76 int main() {
 77     int T(0);
 78     while(~scanf("%s",s) && s[0]!='#') {
 79         T++;
 80         printf("Case %d: ", T);
 81         n = strlen(s) + 1;
 82         build_sa('z' + 1), build_height();
 83         build_st(n - 1);
 84         int len = strlen(s);
 85         if (len == 1) { puts(s); return 0; }
 86         int ans = -1, st = inf, pril = 0;
 87         rep(l, 1, len / 2) {
 88             for (int i = 0; (i + 1) * l < len; i++) {
 89                 int q1 = i * l, q2 = (i + 1) * l;
 90                 int cur_ans = query(min(rnk[q1], rnk[q2]) + 1, max(rnk[q1], rnk[q2]));
 91                 int cur_st = q1;
 92                 int r = l - cur_ans % l;
 93                 cur_ans = cur_ans / l + 1;
 94                 int cnt(0);
 95                 for (int j = q1 - 1; j > q1 - l && s[j] == s[j + l] && j >= 0; j--) {
 96                     cnt++;
 97                     if (cnt == r) {
 98                         cur_ans++;
 99                         cur_st = j;
100                     }
101                     if (rnk[j] < rnk[cur_st]) cur_st = j;
102                 }
103                 if (cur_ans > ans || cur_ans == ans && rnk[cur_st] < rnk[st]) {
104                     ans = cur_ans;
105                     st = cur_st;
106                     pril = l;
107                 }
108             }
109         }
110         int pri = ans * pril;
111         for (int i = st, j = 0; j < pri; j++) printf("%c", s[i + j]);
112         puts("");
113     }
114     return 0;
115 }
View Code

2015年11月23日

  spoj687 <重复次数最多的连续子串长度>

    和上一道题一样,只是不用一位一位往前移动了,少了 l - (k % l) 的值,所以在枚举相邻的i时,也向前l-k%l位,查询LCP即可。

  1 #include <bits/stdc++.h>
  2 #define rep(i, a, b) for (register int i = a; i <= b; i++)
  3 #define drep(i, a, b) for (int i = a; i >= b; i--)
  4 #define REP(i, a, b) for (int i = a; i < b; i++)
  5 #define pb push_back
  6 #define mp make_pair
  7 #define clr(x) memset(x, 0, sizeof(x))
  8 #define xx first
  9 #define yy second
 10 using namespace std;
 11 typedef long long i64;
 12 typedef pair<int, int> pii;
 13 const int inf = 0x3f3f3f3f;
 14 const i64 INF = ~0ULL>>1;
 15 //***************************
 16 
 17 const int maxn = 50005;
 18 char s[maxn];
 19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
 20 void build_sa(int m) {
 21     int *x = t, *y = t2;
 22     REP(i, 0, m) c[i] = 0;
 23     REP(i, 0, n) c[x[i] = s[i]]++;
 24     REP(i, 1, m) c[i] += c[i - 1];
 25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
 26 
 27     for (int k = 1; k <= n; k <<= 1) {
 28         int p(0);
 29         REP(i, n - k, n) y[p++] = i;
 30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 31 
 32         REP(i, 0, m) c[i] = 0;
 33         REP(i, 0, n) c[x[y[i]]]++;
 34         REP(i, 1, m) c[i] += c[i - 1];
 35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
 36 
 37         swap(x, y);
 38         p = 1, x[sa[0]] = 0;
 39         REP(i, 1, n)
 40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
 41         if (p >= n) break;
 42         m = p;
 43     }
 44 }
 45 
 46 int rnk[maxn], height[maxn];
 47 void build_height() {
 48     REP(i, 0, n) rnk[sa[i]] = i;
 49     int k(0);
 50     REP(i, 0, n - 1) {
 51         if (k) k--;
 52         int j = sa[rnk[i] - 1];
 53         while (s[i + k] == s[j + k]) k++;
 54         height[rnk[i]] = k;
 55     }
 56 }
 57 
 58 int Min[maxn][32], Log[maxn];
 59 void build_st(int lim) {
 60     Log[1] = 0;
 61     rep(i, 2, lim) {
 62         Log[i] = Log[i - 1];
 63         if (1 << Log[i] + 1 == i) Log[i]++;
 64     }
 65     drep(i, lim, 1) {
 66         Min[i][0] = height[i];
 67         for (int j = 1; i + (1 << j) - 1 <= lim; j++) 
 68             Min[i][j] = min(Min[i][j - 1], Min[i + (1 << j - 1)][j - 1]);
 69     }
 70 }
 71 int query(int l, int r) {
 72     int len = r - l + 1, k = Log[len];
 73     return min(Min[l][k], Min[r - (1 << k) + 1][k]);
 74 }
 75 
 76 char ch[5];
 77 int main() {
 78     int T;
 79     scanf("%d", &T);
 80     while (T--) {
 81         scanf("%d", &n);
 82         REP(i, 0, n) { scanf("%s", ch); s[i] = ch[0]; }
 83         n++;
 84         build_sa('z' + 1), build_height();
 85         build_st(n - 1);
 86         int len = n - 1;
 87         int ans = -1;
 88         rep(l, 1, len >> 1) {
 89             for (int i = 0; (i + 1) * l < len; i++) {
 90                 int LCP = query(min(rnk[i * l], rnk[(i + 1) * l]) + 1, max(rnk[i * l], rnk[(i + 1) * l]));
 91                 ans = max(ans, LCP / l + 1);
 92                 int q1 = i * l - (l - LCP % l);
 93                 if (q1 < 0) continue;
 94                 LCP = query(min(rnk[q1], rnk[q1 + l]) + 1, max(rnk[q1], rnk[q1 + l]));
 95                 ans = max(ans, LCP / l + 1);
 96             }
 97         }
 98         if (ans == -1) ans = 1;
 99         printf("%d
", ans);
100     }
101 }
View Code

2015年11月24日

  poj2774 <两个字符串的最长公共子串长度>

    首先把两个字符串拼在一起,观察height数组,sa数组中排名相邻的两个字符串若不同属于一个字符串,那么这个height被纳入考虑。

    不相邻的不同属于一个字符串的不需要考虑,假设字符串a排名靠前,字符串b排名靠后,考虑b串,加入b串上面和它不同属于一个串,那么LCP(a, b) 没有LCP(b - 1, b)优;假如b - 1这个串和b同属于一个串,那么LCP(a, b) 没有 LCP(a, b  - 1)优,所以只需要考虑相邻的即可。

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (register int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = 0x3f3f3f3f;
14 const i64 INF = ~0ULL>>1;
15 //***************************
16 
17 const int maxn = 200005;
18 char s[maxn];
19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
20 void build_sa(int m) {
21     int *x = t, *y = t2;
22     REP(i, 0, m) c[i] = 0;
23     REP(i, 0, n) c[x[i] = s[i]]++;
24     REP(i, 1, m) c[i] += c[i - 1];
25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
26 
27     for (int k = 1; k <= n; k <<= 1) {
28         int p(0);
29         REP(i, n - k, n) y[p++] = i;
30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
31 
32         REP(i, 0, m) c[i] = 0;
33         REP(i, 0, n) c[x[y[i]]]++;
34         REP(i, 1, m) c[i] += c[i - 1];
35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
36 
37         swap(x, y);
38         p = 1; x[sa[0]] = 0;
39         REP(i, 1, n)
40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
41         if (p >= n) break;
42         m = p;
43     }
44 }
45 
46 int rnk[maxn], height[maxn];
47 void build_height() {
48     REP(i, 0, n) rnk[sa[i]] = i;
49     int k(0);
50     REP(i, 0, n - 1) {
51         if (k) k--;
52         int j = sa[rnk[i] - 1];
53         while (s[i + k] == s[j + k]) k++;
54         height[rnk[i]] = k;
55     }
56 }
57 
58 char str[maxn >> 1];
59 int main() {
60     scanf("%s", str);
61     memcpy(s, str, sizeof(str));
62     int cur = strlen(str);
63     int k = cur;
64     scanf("%s", str);
65     s[cur++] = '$';
66     for (int i = 0; str[i]; i++) s[cur++] = str[i];
67     n = cur + 1;
68     build_sa('z' + 1); build_height();
69     int ans = -1;
70     REP(i, 1, n) {
71         int l = sa[i - 1], r = sa[i];
72         if (l > r) swap(l, r);
73         if (l < k && r > k) ans = max(ans, height[i]);
74     }
75     printf("%d
", ans);
76     return 0;
77 }
View Code

  ural1517 <两个字符串最长公共子串长度>

    和上一道题一样,不再赘述。

 1 #include <bits/stdc++.h>
 2 #define rep(i, a, b) for (register int i = a; i <= b; i++)
 3 #define drep(i, a, b) for (int i = a; i >= b; i--)
 4 #define REP(i, a, b) for (int i = a; i < b; i++)
 5 #define pb push_back
 6 #define mp make_pair
 7 #define clr(x) memset(x, 0, sizeof(x))
 8 #define xx first
 9 #define yy second
10 using namespace std;
11 typedef long long i64;
12 typedef pair<int, int> pii;
13 const int inf = 0x3f3f3f3f;
14 const i64 INF = ~0ULL>>1;
15 //***************************
16 
17 const int maxn = 200005;
18 char s[maxn];
19 int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
20 void build_sa(int m) {
21     int *x = t, *y = t2;
22     REP(i, 0, m) c[i] = 0;
23     REP(i, 0, n) c[x[i] = s[i]]++;
24     REP(i, 1, m) c[i] += c[i - 1];
25     drep(i, n - 1, 0) sa[--c[x[i]]] = i;
26 
27     for (int k = 1; k <= n; k <<= 1) {
28         int p(0);
29         REP(i, n - k, n) y[p++] = i;
30         REP(i, 0, n) if (sa[i] >= k) y[p++] = sa[i] - k;
31 
32         REP(i, 0, m) c[i] = 0;
33         REP(i, 0, n) c[x[y[i]]]++;
34         REP(i, 1, m) c[i] += c[i - 1];
35         drep(i, n - 1, 0) sa[--c[x[y[i]]]] = y[i];
36 
37         swap(x, y);
38         p = 1; x[sa[0]] = 0;
39         REP(i, 1, n)
40             x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1 : p++;
41         if (p >= n) break;
42         m = p;
43     }
44 }
45 
46 int rnk[maxn], height[maxn];
47 void build_height() {
48     REP(i, 0, n) rnk[sa[i]] = i;
49     int k(0);
50     REP(i, 0, n - 1) {
51         if (k) k--;
52         int j = sa[rnk[i] - 1];
53         while (s[i + k] == s[j + k]) k++;
54         height[rnk[i]] = k;
55     }
56 }
57 
58 int main() {
59     int len;
60     scanf("%d", &len);
61     scanf("%s", s);
62     s[len] = '$';
63     scanf("%s", s + len + 1);
64     n = (len << 1) + 2;
65     build_sa('z' + 1), build_height();
66     int ans = -1, st;
67     REP(i, 1, n) {
68         int q1 = sa[i], q2 = sa[i - 1];
69         if (q1 > q2) swap(q1, q2);
70         if (q1 < len && q2 > len) {
71             if (height[i] > ans) ans = height[i], st = q1;
72         }
73     }
74     while (ans--) putchar(s[st++]);
75     return 0;
76 }
View Code

 

原文地址:https://www.cnblogs.com/y7070/p/4978282.html