后缀数组专题

很久没写过这东西了,复习一波。

3238: [Ahoi2013]差异

链接

单调栈维护height数组,由于height是递增的,所以维护单调栈中维护每个height出现的次数。(还可以两遍单调栈求一个点是最小值的区间)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<cctype>
 7 #include<set>
 8 #include<queue>
 9 #include<vector>
10 #include<map>
11 using namespace std;
12 typedef long long LL;
13  
14 inline int read() {
15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
17 }
18  
19 const int N = 500005;
20  
21 char s[N];
22 int t1[N], t2[N], c[N], sa[N], rnk[N], height[N], m = 130, n;
23 LL sk[N], cnt[N];
24  
25 void getsa() {
26     int *x = t1, *y = t2, i, p;
27     for (i = 1; i <= m; ++i) c[i] = 0;
28     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
29     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
30     for (i = 1; i <= n; ++i) sa[c[x[i]]--] = i;
31     for (int k = 1; k <= n; k <<= 1) {
32         p = 0;
33         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
34         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
35         for (i = 1; i <= m; ++i) c[i] = 0;
36         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
37         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
38         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
39         swap(x, y);
40         p = 2;
41         x[sa[1]] = 1;
42         for (i = 2; i <= n; ++i) 
43             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
44         if (p > n) break;
45         m = p;
46     }
47 }
48 void getheight() {
49     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
50     int k = 0;
51     height[1] = 0;
52     for (int i = 1; i <= n; ++i) {
53         if (rnk[i] == 1) continue;
54         if (k) k --;
55         int j = sa[rnk[i] - 1];
56         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
57         height[rnk[i]] = k;
58     }
59 }
60 int main() {
61     scanf("%s", s + 1);
62     n = strlen(s + 1);
63     getsa();
64     getheight();
65     LL ans = 0;
66     for (int i = 1; i <= n; ++i) ans += 1ll * (n - 1) * i;
67     int top = 0;LL now = 0;
68     for (int i = 2; i <= n; ++i) {
69         LL tmp = 1;
70         while (top && sk[top] >= height[i]) {
71             now -= 1ll * cnt[top] * sk[top]; tmp += cnt[top]; top --;
72         }
73         sk[++top] = height[i]; cnt[top] = tmp; now += 1ll * height[i] * tmp;
74         ans -= now * 2;
75     }
76     cout << ans;
77     return 0;
78 }
View Code

CF 1090 J. Two Prefixes

链接

kmp+后缀数组。

正难则反,用总的减去出现了多次的。枚举第二个串,那么考虑那些串是已经被计算过的,考虑这个前缀的bordor,如果第一个串可以存在1~n-bordor的字符,那么就是以前计算过的。

后缀数组求lcp。

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cctype>
  7 #include<set>
  8 #include<queue>
  9 #include<vector>
 10 #include<map>
 11 using namespace std;
 12 typedef long long LL;
 13 
 14 inline int read() {
 15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 17 }
 18 
 19 const int N = 200005;
 20 char s[N], a[N], b[N];
 21 int t1[N], t2[N], c[N], sa[N], height[N], Log[N], p[N], f[N][20], rnk[N], n, m = 130, la, lb;
 22 LL sum[N];
 23 
 24 void getsa() {
 25     int *x = t1, *y = t2, i, p;
 26     for (i = 1; i <= m; ++i) c[i] = 0;
 27     for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
 28     for (i = 1; i <= m; ++i) c[i] += c[i - 1];
 29     for (i = n; i >= 1; --i) sa[c[x[i]]--] = i;
 30     for (int k = 1; k <= n; k <<= 1) {
 31         p = 0;
 32         for (i = n - k + 1; i <= n; ++i) y[++p] = i;
 33         for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
 34         for (i = 1; i <= m; ++i) c[i] = 0;
 35         for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
 36         for (i = 1; i <= m; ++i) c[i] += c[i - 1];
 37         for (i = n; i >= 1; --i) sa[c[x[y[i]]]--] = y[i];
 38         swap(x, y);
 39         p = 2;
 40         x[sa[1]] = 1;
 41         for (i = 2; i <= n; ++i) 
 42             x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
 43         if (p > n) break ;
 44         m = p;
 45     }
 46 }
 47 void getheight() {
 48     for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
 49     int k = 0;
 50     height[1] = 0;
 51     for (int i = 1; i <= n; ++i) {
 52         if (rnk[i] == 1) continue;
 53         if (k) k --;
 54         int j = sa[rnk[i] - 1];
 55         while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
 56         height[rnk[i]] = k;
 57     }
 58 }
 59 void rmq() {
 60     Log[0] = -1;
 61     for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1; 
 62     for (int i = 1; i <= n; ++i) f[i][0] = height[i];
 63     for (int j = 1; j <= Log[n]; ++j) 
 64         for (int i = 1; i + (1 << j) - 1 <= n; ++i) 
 65             f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
 66 }
 67 int LCP(int l,int r) {
 68     if (l > r) swap(l, r);
 69     l ++;
 70     int k = Log[r - l + 1];
 71     return min(f[l][k], f[r - (1 << k) + 1][k]);
 72 }
 73 int main() {
 74     scanf("%s%s", a + 1, b + 1);
 75     la = strlen(a + 1), lb = strlen(b + 1);
 76     n = la + lb;
 77     for (int i = 1; i <= la; ++i) s[i] = a[i];
 78     for (int i = 1; i <= lb; ++i) s[i + la] = b[i];
 79     getsa();
 80     getheight();
 81     rmq();
 82 
 83     for (int i = 2; i <= la; ++i) {
 84         int len = min(LCP(rnk[i], rnk[la + 1]), la - i + 1);
 85         sum[len] ++;
 86     }
 87     for (int i = la; i >= 1; --i) sum[i] += sum[i + 1];
 88     p[1] = 0;
 89     for (int i = 2; i <= lb; ++i) {
 90         int j = p[i - 1];
 91         while (j && b[j + 1] != b[i]) j = p[j];
 92         if (b[j + 1] == b[i]) j ++;
 93         p[i] = j;
 94     }
 95     LL ans = 1ll * la * lb;
 96     for (int i = 2; i <= lb; ++i) 
 97         if (p[i]) ans -= sum[i - p[i]];
 98     cout << ans;
 99     return 0;
100 }
View Code

猜你喜欢

转载自www.cnblogs.com/mjtcn/p/10211803.html