字尾陣列專題
阿新 • • 發佈:2019-01-02
很久沒寫過這東西了,複習一波。
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<setView Code> 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';returnx*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 }
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