platform(SA +线段树二分 or 后缀树+倍增)

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);
}

猜你喜欢

转载自blog.csdn.net/Cold_Chair/article/details/81747460
今日推荐