bzoj 3238[Ahoi2013]差异 - 后缀数组 + 单调栈
3238: [Ahoi2013]差异
Time Limit: 20 Sec Memory Limit: 512 MBDescription
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 }