您的位置:首页 > 其它

BZOJ3238 [Ahoi2013]差异

2015-05-03 22:17 218 查看
首先把后缀数组和height数组都搞出来。。。

然后用两个单调栈维护$[l, r]$表示对于一个点$x$,满足$height[x] \le height[l..x] \ \&\&\ height[x] < height[x..r]$的最小的$l$和最大的$r$

这样子就可以保证不会重复计算了

/**************************************************************
Problem: 3238
User: rausen
Language: C++
Result: Accepted
Time:4496 ms
Memory:20336 kb
****************************************************************/

#include <cstdio>
#include <cstring>

using namespace std;
typedef long long ll;
const int N = 5e5 + 5;

int a
, len;
int sa
, rank
, height
;

inline void Sort(int *a, int *b, int *c, int n, int m) {
static int i, sum
;
for (i = 0; i <= m; ++i) sum[i] = 0;
for (i = 0; i < n; ++i) ++sum[c[a[i]]];
for (i = 1; i <= m; ++i) sum[i] += sum[i - 1];
for (i = n - 1; ~i; --i)
b[--sum[c[a[i]]]] = a[i];
}

void make_sa(int *s) {
int i, j;
static int x
, y
;
for (i = 0; i < len; ++i) x[i] = s[i], rank[i] = i;
Sort(rank, sa, x, len, 30);
rank[sa[0]] = 1;
for (i = 1; i < len; ++i)
rank[sa[i]] = rank[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]]);
for (i = 1; i <= len; i <<= 1) {
for (j = 0; j < len; ++j)
x[j] = rank[j], y[j] = j + i < len ? rank[j + i] : 0, sa[j] = j;
Sort(sa, rank, y, len, len), Sort(rank, sa, x, len, len);
rank[sa[0]] = 1;
for (j = 1; j < len; ++j)
rank[sa[j]] = rank[sa[j - 1]] + (x[sa[j]] != x[sa[j - 1]] || y[sa[j]] != y[sa[j - 1]]);
if (rank[sa[len - 1]] == len) return;
}
}

void make_height() {
int i, j;
for (i = j = 0; i < len; ++i) {
if (j) --j;
if (rank[i] != 1)
while (a[i + j] == a[sa[rank[i] - 2] + j]) ++j;
height[rank[i]] = j;
}
}

ll work() {
int i;
ll res;
static int s
, top, l
, r
;
for (res = 0, i = 1; i <= len; ++i) res += 1ll * i * (len - 1);
for (s[top = 0] = 0, i = 1; i <= len; ++i) {
while (height[i] <= height[s[top]] && top) --top;
l[i] = s[top] + 1;
s[++top] = i;
}
for (s[top = 0] = len + 1, i = len; i; --i) {
while (height[i] < height[s[top]] && top) --top;
r[i] = s[top] - 1;
s[++top] = i;
}
for (i = 1; i <= len; ++i)
res -= 2ll * (i - l[i] + 1) * (r[i] - i + 1) * height[i];
return res;
}

int main() {
int i;
char ch;
for (len = 0; ;) {
ch = getchar();
if ('a' <= ch && ch <= 'z') a[len++] = ch - 'a' + 1;
else break;
}
make_sa(a);
make_height();
printf("%lld\n", work());
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: