Description:
题解:
有一个非常显然(并不)的结论。
就是每一个后缀只有至多一个前缀满足条件。
因为对于一个后缀的所有前缀来说来说,随着长度的增加,排名递减,但是val的和不递增,因此只有一个。
很容易想到对于每一个后缀二分一下,现在问题在于如何求一个子串的rank?
去重?这不是SAM干的事?可是直接用SAM复杂度就乘了n。
SAM的fail链就形成原串的反串的后缀树,所以我们对原串的反串建SAM,fail链即形成了原串的后缀树。
我们想想后缀树是什么?
所有后缀放到一个trie里,只有一个子节点的节点缩起来。
后缀树的每个点代表一个范围,同SAM。
先在后缀树上求出每个点的rank,接着倍增调到对应的范围的那个点,算一算即可。
也可以建SA,求height,线段树二分到第一个小于长度的height,算一算就行了。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define i0 i + i
#define i1 i + i + 1
using namespace std;
const int N = 2e5 + 5;
char s[N];
int n, m, SA[N], rank[N], he[N], tax[N], tp[N];
ll sum[N];
void RSort() {
for (int i = 0; i <= m; i ++) tax[i] = 0;
for (int i = 1; i <= n; i ++) tax[rank[tp[i]]] ++;
for (int i = 1; i <= m; i ++) tax[i] += tax[i-1];
for (int i = n; i >= 1; i --) SA[tax[rank[tp[i]]] --] = tp[i];
}
int cmp(int *f, int x, int y, int w) { return f[x] == f[y] && f[x + w] == f[y + w]; }
void Suffix() {
for (int i = 1; i <= n; i ++) rank[i] = s[i], tp[i] = i;
m = 127 ,RSort();
for (int w = 1, p = 1, i; p < n; w += w, m = p) {
for (p = 0, i = n - w + 1; i <= n; i ++) tp[++ p] = i;
for (i = 1; i <= n; i ++) if (SA[i] > w) tp[++ p] = SA[i] - w;
RSort(), swap(rank, tp), rank[SA[1]] = p = 1;
for (i = 2; i <= n; i ++) rank[SA[i]] = cmp(tp, SA[i], SA[i - 1], w) ? p : ++ p;
}
int j, k = 0;
for(int i = 1; i <= n; he[rank[i ++]] = k)
for( k = k ? k - 1 : k, j = SA[rank[i] - 1]; s[i + k] == s[j + k]; ++ k);
}
int t[N * 4], pl, pr, pz, px;
ll v[N], cnt[N];
void bt(int i, int x, int y) {
if(x == y) {t[i] = he[x]; return;}
int m = x + y >> 1;
bt(i0, x, m); bt(i1, m + 1, y);
t[i] = min(t[i0], t[i1]);
}
void fi(int i, int x, int y) {
if(y < pl || x > pr) return;
if(x == y) {if(t[i] < pz) px = x; return;}
int m = x + y >> 1;
if(x >= pl && y <= pr) {
if(t[i1] < pz) fi(i1, m + 1, y);
if(px) return;
if(t[i0] < pz) fi(i0, x, m);
} else {
fi(i1, m + 1, y);
if(px) return;
fi(i0, x, m);
}
}
ll grank(int x, int y) {
pl = 1, pr = rank[x], pz = y - x + 1, px = 0;
fi(1, 1, n);
return cnt[n] - (cnt[px - 1] + (y - x + 1) - he[px]) + 1;
}
struct node {
int x, y;
} b[N]; int b0;
int main() {
freopen("platform.in", "r", stdin);
freopen("platform.out", "w", stdout);
scanf("%s", s + 1); n = strlen(s + 1);
fo(i, 1, n) scanf("%lld", &v[i]), v[i] += v[i - 1];
Suffix(); bt(1, 1, n);
cnt[1] = n - SA[1] + 1;
fo(i, 2, n) cnt[i] = cnt[i - 1] + (n - SA[i] + 1) - he[i];
fo(i, 1, n) {
int as = 0;
for(int l = i, r = n; l <= r; ) {
int m = l + r >> 1;
if(grank(i, m) >= v[m] - v[i - 1])
as = m, l = m + 1; else r = m - 1;
}
if(as && grank(i, as) == v[as] - v[i - 1])
b[++ b0].x = i, b[b0].y = as;
}
printf("%d\n", b0);
fo(i, 1, b0) printf("%d %d\n", b[i].x, b[i].y);
}