[BZOJ3998]弦论

题目链接BZOJ3998

题目大意
求长度为 N 的字符串的第K小子串。

分析
在后缀自动机上找第 K 小,用right集合的性质和 dfs 搞一搞就好了,可以自己YY一下。(意识流题解)

上代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 5e5 + 10;

int len, T, K;
int cnt, S, last;
int ch[N << 1][26], link[N << 1], maxl[N << 1], rig[N << 1];
inline void extend(int c) {
    int now = ++cnt, tmp = last;
    maxl[last = now] = maxl[tmp] + 1, rig[now] = 1;
    for (; tmp && !ch[tmp][c]; tmp = link[tmp]) ch[tmp][c] = now;
    if (!tmp) return link[now] = S, void(0);
    if (maxl[ch[tmp][c]] == maxl[tmp] + 1)
        return link[now] = ch[tmp][c], void(0);
    int r = ++cnt, q = ch[tmp][c];
    maxl[r] = maxl[tmp] + 1;
    link[r] = link[q], link[q] = link[now] = r;
    memcpy(ch[r], ch[q], sizeof(ch[q]));
    for (; tmp && ch[tmp][c] == q; tmp = link[tmp]) ch[tmp][c] = r;
}

int dsc[N << 1], sum[N];
void calcRig() {
    for (int i = 1; i <= cnt; ++i) sum[maxl[i]]++;
    for (int i = 1; i <= len; ++i) sum[i] += sum[i - 1];
    for (int i = 1; i <= cnt; ++i) dsc[sum[maxl[i]]--] = i;
    for (int i = cnt; i >= 1; --i) rig[link[dsc[i]]] += rig[dsc[i]];
}

int size[N << 1];
void dfs(int a) {
    if (size[a]) return;
    size[a] = rig[a];
    for (int i = 0; i < 26; ++i) {
        int now = ch[a][i];
        if (!now) continue;
        dfs(now), size[a] += size[now];
    }
}
void search(int a, int k) {
    if (k > size[a]) puts("-1"), exit(0);
    if (k -= rig[a], k <= 0) puts(""), exit(0);
    for (int i = 0; i < 26; ++i) {
        int now = ch[a][i];
        if (!now) continue;
        if (size[now] < k) k -= size[now];
        else putchar(i + 'a'), search(now, k);
    }
}

char ss[N];
int main() {
    S = cnt = last = 1;
    scanf("%s", ss + 1), len = strlen(ss + 1);
    for (int i = 1; i <= len; ++i) extend(ss[i] - 'a');
    scanf("%d %d", &T, &K);
    if (T) calcRig();
    else for (int i = 2; i <= cnt; ++i) rig[i] = 1;
    rig[S] = 0, dfs(S), search(S, K);
    return 0;
}

以上

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值