题意
- 给你一个字符串 S S S,对于 r ∈ [ 0 , n ) r\in[0,n) r∈[0,n),求有多少对位置 ( i , j ) (i,j) (i,j)满足 ∀ k ∈ [ 0 , r ] \forall k\in[0,r] ∀k∈[0,r],有 S i + k = S j + k S_{i+k}=S_{j+k} Si+k=Sj+k,并求出这些位置中任意两位置权值最大值。
首先如果两个位置对 r r r满足条件,那么它们对 k ∈ [ 0 , r ) k\in[0,r) k∈[0,r)也是满足条件的,我们只需要考虑恰好为 r r r时的答案,再做一遍后缀和与后缀最大值就好了。
我们先对这个串建出后缀数组,那么每个 r r r实际上就是两个后缀的最长公共前缀的长度,又因为两个后缀的最长公共前缀时对于连续一段排名的高度数组取最小值,所以我们可以把每个位置的权值映射到后缀对应的排名后按高度数组进行分类来统计答案。我们可以用并查集来维护这个过程,一个并查集内的元素一定满足任意两个元素的最长公共前缀长度都大于等于 r r r,那么每次合并两个并查集的时候只要统计新增加的答案对数即可,复杂度 O ( n log n ) O(\text {n log n}) O(n log n)。
#include <bits/stdc++.h>
#define ll long long
#define chkmax(a, b) (a < b ? a = b, 1 : 0)
#define chkmin(a, b) (a > b ? a = b, 1 : 0)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define Forr(i, a, b) for (int i = a; i >= b; -- i)
using namespace std;
const int N = 3e5 + 7;
int n, a[N];
char S[N];
struct Suffix_Array {
int SA[N], rk[N << 1], tp[N << 1];
int tong[N], m, height[N];
void Radix_Sort() {
For(i, 1, m) tong[i] = 0;
For(i, 1, n) ++ tong[rk[tp[i]]];
For(i, 2, m) tong[i] += tong[i - 1];
Forr(i, n, 1) SA[tong[rk[tp[i]]] --] = tp[i];
}
void build() {
For(i, 1, n) m = max(m, rk[i] = S[i]), tp[i] = i;
Radix_Sort();
for (int len = 1; len < n; len <<= 1) {
int cnt = 0;
For(i, n - len + 1, n) tp[++ cnt] = i;
For(i, 1, n) if (SA[i] > len) tp[++ cnt] = SA[i] - len;
Radix_Sort(), swap(rk, tp), rk[SA[1]] = m = 1;
For(i, 2, n) {
if (tp[SA[i]] ^ tp[SA[i - 1]] || tp[SA[i] + len] ^ tp[SA[i - 1] + len]) ++ m;
rk[SA[i]] = m;
}
if (m == n) break;
}
For(i, 1, n) {
int now = max(0, height[rk[i - 1]] - 1);
while (now < n && S[i + now] == S[SA[rk[i] - 1] + now]) ++ now;
height[rk[i]] = now;
}
}
} SA;
ll ans1[N], ans2[N];
struct node {
int h, x, y;
bool operator < (const node &T) const {
return h > T.h;
}
} A[N];
struct Union_Find_Set {
int fa[N], sz[N], mx[N], mn[N];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
void merge(int now, int x, int y) {
x = find(x), y = find(y);
if (x ^ y) {
ans1[now] += 1ll * sz[x] * sz[y];
chkmax(ans2[now], max(1ll * mx[x] * mx[y], 1ll * mn[x] * mn[y]));
chkmax(mx[x], mx[y]), chkmin(mn[x], mn[y]), sz[x] += sz[y], fa[y] = x;
}
}
} Set;
int main() {
//freopen("2133.in", "r", stdin);
//freopen("2133.out", "w", stdout);
scanf("%d%s", &n, S + 1), SA.build();
For(i, 1, n) scanf("%d", &a[i]);
For(i, 2, n) A[i - 1] = (node) {SA.height[i], i - 1, i};
For(i, 1, n) {
Set.fa[i] = i, Set.sz[i] = 1;
Set.mx[i] = Set.mn[i] = a[SA.SA[i]];
ans2[i] = LLONG_MIN;
}
sort(A + 1, A + n);
Forr(i, A[1].h, 0) {
ans1[i] += ans1[i + 1];
chkmax(ans2[i], ans2[i + 1]);
for (static int j = 1; j < n && A[j].h == i; ++ j)
Set.merge(i, A[j].x, A[j].y);
}
For(i, 0, n - 1) {
if (ans1[i]) printf("%lld %lld\n", ans1[i], ans2[i]);
else puts("0 0");
}
return 0;
}