bzoj 3238[Ahoi2013]差异 - 后缀数组 + 单调栈

3238: [Ahoi2013]差异

Time Limit: 20 Sec  Memory Limit: 512 MB

Description

Input

一行,一个字符串S

Output

一行,一个整数,表示所求值

Sample Input

cacao

Sample Output

54

HINT

2<=N<=500000,S由小写英文字母组成

 

因为要求LCP,还有后缀,所以要用到后缀数组。

求出height, 对于排名为 i 的后缀, 他和前面每一个后缀的贡献是 len[i] + len[k] - lcp(i, k)

len[k] 可以用前缀和算, 和前面所有后缀的lcp的和可以用单调栈维护,思路和[Haoi2016]找相同字符 是一样的

于是就解决了。

 

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define LL long long
  6 
  7 using namespace std;
  8 
  9 const int MAXN = 6e5 + 10;
 10 
 11 LL m, len;
 12 LL ans = 0;
 13 char s[MAXN];
 14 
 15 LL h[MAXN];
 16 LL c[MAXN], cur[MAXN], ra[MAXN], tp[MAXN], SA[MAXN];
 17 
 18 struct ss {
 19     int id;
 20     LL sum;
 21 } sta[MAXN];
 22 
 23 inline LL read()
 24 {
 25     LL x = 0, w = 1; char ch = 0;
 26     while(ch < '0' || ch > '9') {
 27         if(ch == '-') {
 28             w = -1;
 29         }
 30         ch = getchar();
 31     }
 32     while(ch >= '0' && ch <= '9') {
 33         x = x * 10 + ch - '0';
 34         ch = getchar();
 35     }
 36     return x * w;
 37 }
 38 
 39 void solve(int x)
 40 {
 41     for(int i = 1; i <= x; i++) {
 42         c[i] = 0;
 43     }
 44     for(int i = 1; i <= len; i++) {
 45         c[ra[tp[i]]]++;
 46     }
 47     for(int i = 1; i <= x; i++) {
 48         c[i] += c[i - 1];
 49     }
 50     for(int i = len; i >= 1; i--) {
 51         SA[c[ra[tp[i]]]--] = tp[i];
 52     }
 53 }
 54 
 55 void copy()
 56 {
 57     for(int i = 1; i <= len; i++) {
 58         cur[i] = ra[i];
 59     }
 60 }
 61 
 62 void suffix()
 63 {
 64     for(int i = 1; i <= len; i++) {
 65         ra[i] = s[i];
 66         tp[i] = i;
 67     }
 68     solve(m = 128);
 69     for(int w = 1, p = 0; p < len; w += w, m = p) {
 70         p = 0;
 71         for(int j = len - w + 1; j <= len; j++) {
 72             tp[++p] = j;
 73         }
 74         for(int i = 1; i <= len; i++) {
 75             if(SA[i] > w) {
 76                 tp[++p] = SA[i] - w;
 77             }
 78         }
 79         solve(m);
 80         copy();
 81         ra[SA[1]] = p = 1; 
 82         for(int i = 2; i <= len; i++) {
 83             if(cur[SA[i]] == cur[SA[i - 1]] && cur[SA[i] + w] == cur[SA[i - 1] + w]) {
 84                 ra[SA[i]] = p;
 85             } else {
 86                 ra[SA[i]] = ++p;
 87             }
 88         }
 89     }
 90     int k = 0;
 91     for(int i = 1; i <= len; i++) {
 92         if(k) {
 93             k--;
 94         }
 95         int j = SA[ra[i] - 1];
 96         while(s[i + k] == s[j + k]) {
 97             k++;
 98         }
 99         h[ra[i]] = k;
100     }
101 }
102 
103 void cal()
104 {
105     int top = 1;
106     LL sum = 0;
107     for(int i = 1; i <= len; i++) {
108         while(top > 1 && h[i] < h[sta[top - 1].id]) {
109             top--;
110         }
111         sta[top].id = i;
112         sta[top].sum = sta[top - 1].sum + (i - sta[top - 1].id) * h[i];
113         top++;
114         ans += (i - 1) * (len - SA[i] + 1) + sum - 2 * sta[top - 1].sum;
115         sum += len - SA[i] + 1;
116     }
117     printf("%lld\n", ans);
118 }
119 
120 int main()
121 {
122     scanf("%s", s + 1);
123     len = strlen(s + 1);
124     suffix();
125     cal();
126 }
View Code

 

posted @ 2018-03-27 19:42  大财主  阅读(164)  评论(1编辑  收藏  举报