[BZOJ2555] [TJOI2015]弦论 && 后缀自动机

本文介绍了一个使用后缀自动机解决字符串统计问题的方法。通过详细的代码解析,展示了如何构建后缀自动机,并利用它来高效地进行字符串匹配与统计。文章包含完整的实现流程及关键步骤说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本来以为是一个多么神的题 弦论 多么高大上 

结果 居然是后缀自动机的统计 水水的

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define SF scanf
#define PF printf
#define idx(c) (c-'a')
using namespace std;
typedef long long LL;
const int MAXN = 500000;
int T, K;
char s[MAXN+10];
struct SAM {
    int fa[MAXN*2+10], ch[MAXN*2+10][26], step[MAXN*2+10];
    int val[MAXN*2+10], Q[MAXN*2+10], tmp[MAXN*2+10], cnt[MAXN*2+10];
    int ncnt, last, length;
    SAM () { last = ++ncnt; }
    void extend(int c) {
        int p = last, np = last = ++ncnt;
        step[np] = step[p]+1; val[np] = 1;
        while(!ch[p][c] && p) ch[p][c] = np, p = fa[p];
        if(!p) fa[np] = 1;
        else {
            int q = ch[p][c], nq;
            if(step[q] == step[p]+1) fa[np] = q;
            else {
                nq = ++ncnt;
                step[nq] = step[p]+1;
                memcpy(ch[nq], ch[q], sizeof(ch[nq]));
                fa[nq] = fa[q];
                fa[q] = fa[np] = nq;
                while(ch[p][c] == q) ch[p][c] = nq, p = fa[p];
            }
        }
    }
    void build(char *s) {
        length = strlen(s);
        for(int i = 0; i < length; i++)
            extend(idx(s[i]));
    }
    void sort() {
        for(int i = 1; i <= ncnt; i++) tmp[step[i]]++;
        for(int i = 1; i <= length; i++) tmp[i] += tmp[i-1];
        for(int i = ncnt; i; i--) Q[tmp[step[i]]--] = i;
    }
    void pre() {
        for(int i = ncnt; i; i--) 
            if(T) val[fa[Q[i]]] += val[Q[i]];
            else val[Q[i]] = 1;
        val[1] = 0;
        for(int i = ncnt; i; i--) {
            int u = Q[i];
            cnt[u] = val[u];
            for(int j = 0; j < 26; j++) cnt[u] += cnt[ch[u][j]];
        }
    }
    void dfs(int u, int K) {
        if(K <= val[u]) return ;
        K -= val[u];
        for(int i = 0; i < 26; i++)
            if(ch[u][i]) {
                if(K <= cnt[ch[u][i]]) {
                    putchar(i+'a');
                    dfs(ch[u][i], K);
                    return ;
                }
                K -= cnt[ch[u][i]];
            }
    }
} sam;
int main() {
    SF("%s", s);
    SF("%d%d", &T, &K);
    sam.build(s);
    sam.sort();
    sam.pre();
    if(K > sam.cnt[1]) puts("-1");
    else sam.dfs(1, K);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值