【题目描述】
有一个长度为n的仅包含小写字母的字符串$S$,下标范围为$[1,n]$.

现在有若干组询问,对于每一个询问,我们给出若干个后缀(以其在$S$中出现的起始位置来表示),求这些后缀两两之间的LCP(LongestCommonPrefix)的长度之和.一对后缀之间的LCP长度仅统计一遍.

【输入格式】
第一行两个正整数$n,m$,分别表示$S$的长度以及询问的次数.

接下来一行有一个字符串$S$.

接下来有$m$组询问,对于每一组询问,均按照以下格式在一行内给出:

首先是一个整数$t$,表示共有多少个后缀.接下来$t$个整数分别表示$t$个后缀在字符串$S$中的出现位置.

【输出格式】
对于每一组询问,输出一行一个整数,表示该组询问的答案.由于答案可能很大,仅需要输出这个答案对于$23333333333333333$(一个巨大的质数)取模的余数

题解

这不是和 差异「AHOI2013」 几乎一模一样吗。。。那题就相当于询问是$1\sim n$的所有后缀 然后式子稍微变变形

传送门

这题也是一样 先建好后缀数组 对于每组询问 先按照后缀数组的$rnk$进行排序 然后去重 然后用ST表来求出排序后相邻两个后缀的LCP

剩下的单调栈DP就跟上面那题一样了 不想再敲一遍了 请点上面传送门 看解法一:后缀数组

唯一的区别就是多个ST表。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <bits/stdc++.h>
#define N 500005
using namespace std;
typedef long long ll;

const ll mod = 23333333333333333;
int n, m, t;
char s[500005];
int sa[N], sum[N], rnk[N], sa2[N], key[N], height[N], q[N], tmp[N], stk[N], top;
ll f[N], ans;

inline bool check(int *num, int a, int b, int l) {
return num[a] == num[b] && num[a+l] == num[b+l];
}

inline void DA(int _m) {
int i, j, p;
for (i = 1; i <= _m; i++) sum[i] = 0;
for (i = 1; i <= n; i++) sum[rnk[i]=s[i]]++;
for (i = 2; i <= _m; i++) sum[i] += sum[i-1];
for (i = n; i >= 1; i--) sa[sum[rnk[i]]--] = i;
for (j = 1, p = 0; j <= n; j <<= 1, _m = p) {
p = 0; for (i = n - j + 1; i <= n; i++) sa2[++p] = i;
for (i = 1; i <= n; i++) if (sa[i] > j) sa2[++p] = sa[i] - j;
for (i = 1; i <= n; i++) key[i] = rnk[sa2[i]];
for (i = 1; i <= _m; i++) sum[i] = 0;
for (i = 1; i <= n; i++) sum[key[i]]++;
for (i = 2; i <= _m; i++) sum[i] += sum[i-1];
for (i = n; i >= 1; i--) sa[sum[key[i]]--] = sa2[i];
for (swap(rnk, sa2), p = 2, rnk[sa[1]] = 1, i = 2; i <= n; i++) {
rnk[sa[i]] = check(sa2, sa[i-1], sa[i], j) ? p - 1 : p++;
}
}
}

inline void geth() {
ll p = 0;
for (int i = 1; i <= n; i++) rnk[sa[i]] = i;
for (int i = 1; i <= n; i++) {
if (p) p--;
int j = sa[rnk[i]-1];
while (s[i + p] == s[j + p]) p++;
height[rnk[i]] = p;
}
}

int st[N][21];

void preST() {
for (int i = 1; i <= n; i++) st[i][0] = height[i];
for (int l = 1; (1 << l) <= n; l++) {
for (int i = 1; i <= n - (1 << l) + 1; i++) {
st[i][l] = min(st[i][l-1], st[i+(1<<(l-1))][l-1]);
}
}
}

inline int query(int x, int y) {
int l = log2(y - x + 1);
return min(st[x][l], st[y - (1 << l) + 1][l]);
}

inline bool cmp(int x, int y) {
return rnk[x] < rnk[y];
}

int main() {
scanf("%d %d %s", &n, &m, s + 1);
DA(128);
geth();
preST();
for (int i = 1; i <= m; i++) {
scanf("%d", &t);
ans = 0;
for (int j = 1; j <= t; j++) scanf("%d", &q[j]);
sort(q + 1, q + t + 1, cmp);
t = unique(q + 1, q + t + 1) - q - 1;
for (int j = 2; j <= t; j++) {
tmp[j] = query(rnk[q[j-1]] + 1, rnk[q[j]]);
}
stk[top=1] = 1;
for (int j = 2; j <= t; j++) {
while (top && tmp[stk[top]] > tmp[j]) top--;
f[j] = f[stk[top]] + (j - stk[top]) * tmp[j];
stk[++top] = j;
ans += f[j];
}
printf("%lld\n", ans);
}
return 0;
}

评论