# BZOJ4516: [Sdoi2016]生成魔咒

## 题解

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 100010;

ll ans = 0;
int n, m, a[N], b[N], f[N][18], LG[N];
int sa[N], height[N], rnk[N], tp[N], tong[N];
set<int> s;

for(int i = 1; i <= m; ++i) tong[i] = 0;
for(int i = 1; i <= n; ++i) tong[rnk[i]]++;
for(int i = 1; i <= m; ++i) tong[i] += tong[i - 1];
for(int i = n; i; --i) sa[tong[rnk[tp[i]]]--] = tp[i];
}

void suffix_sort() {
for(int i = 1; i <= n; ++i) rnk[i] = a[i], tp[i] = i;
for(int w = 1, p = 1; p < n && w <= n; w <<= 1, m = p) {
p = 0;
for(int i = 1; i <= w; ++i) tp[++p] = n - w + i;
for(int i = 1; i <= n; ++i) if(sa[i] > w) tp[++p] = sa[i] - w;
radix_sort(); swap(tp, rnk); rnk[sa[1]] = p = 1;
for(int i = 2; i <= n; ++i)
rnk[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w]) ? p : ++p;
}
for(int i = 1, k = 0; i <= n; ++i) {
if(k) --k;
int j = sa[rnk[i] - 1];
while(a[i + k] == a[j + k] && i + k <= n && j + k <= n) ++k;
height[rnk[i]] = k;
}
}

int query(int l, int r) {
int k = LG[r - l + 1];
return min(f[l][k], f[r - (1 << k) + 1][k]);
}

int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]), b[i] = a[i];
sort(b + 1, b + n + 1);
for(int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
reverse(a + 1, a + n + 1); suffix_sort();
LG[2] = 1;
for(int i = 3; i <= n; ++i) LG[i] = LG[i >> 1] + 1;
for(int j = 1; j <= n; ++j) f[j][0] = height[j];
for(int j = 1; j <= 19; ++j) {
for(int i = 1; i + (1 << j) - 1 <= n; ++i)
f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
ans = 0;
for(int i = n; i; --i) {
set<int>::iterator it = s.insert(rnk[i]).first, p1 = it, p2 = it;
if(it != s.begin()) {
p1--;
ans += query(*p1 + 1, rnk[i]);
if(++p2 != s.end()) {
ans += query(rnk[i] + 1, *p2);
ans -= query(*p1 + 1, *p2);
}
} else if(++p2 != s.end())
ans += query(rnk[i] + 1, *p2);
printf("%lld\n", 1LL * (n - i + 1) * (n - i + 2) / 2LL - ans);
}
return 0;
}

posted @ 2019-12-15 20:25  henry_y  阅读(121)  评论(0编辑  收藏  举报