SPOJ SUBLEX

求字典序第k大字串

SAM的节点和转移所构成的是一个DAG,并且SAM从起点开始的每一条路径都是模式串的一个字串,根据这两个性质在SAM上dfs即可

#include<bits/stdc++.h>
using namespace std;

const int maxn = 91234*2 ,mlen = 26;
char tem[maxn];

struct Sam{
    int len[maxn],fa[maxn],nex[maxn][mlen];
    int siz[maxn];
    int _cnt,root,omg;
    int newNode(int L = 0){
        len[_cnt] = L;
        memset(nex[_cnt],fa[_cnt] = -1,sizeof(nex[_cnt]));
        return _cnt++;
    }
    void init(){
        _cnt = 0;
        root = omg = newNode();
    }
    void extend(int x){
        int ox = newNode(len[omg]+1);
        while(omg != -1 && nex[omg][x] == -1){
            nex[omg][x] = ox;
            omg = fa[omg];
        }
        if(omg == -1) fa[ox] = root;
        else{
            int omgx = nex[omg][x];
            if(len[omgx] == len[omg]+1) fa[ox] = omgx;
            else{
                int mgx = newNode(len[omg]+1);
                for(int i=0;i<mlen;i++)
                    nex[mgx][i] = nex[omgx][i];
                fa[mgx] = fa[omgx];
                fa[omgx] = fa[ox] = mgx;
                while(omg != -1 && nex[omg][x] == omgx)
                    nex[omg][x] = mgx,omg = fa[omg];
            }
        }
        omg = ox;
    }
    void out(){
        for(int i=0;i<_cnt;i++){
            printf("id = %d fa = %d len = %d siz = %d: ",i,fa[i],len[i],siz[i]);
            for(int j=0;j<5;j++){
                printf("(%c,%2d) ",j + 'a',nex[i][j]);
            }
            puts("");
        }
    }
    void build(char *arr){
        init();
        for(int i=0;arr[i];i++){
            extend(arr[i] - 'a');
        }
    }
    void initDfs(int st = -1){
        if(st == -1){
            st = root;
            memset(siz,-1,sizeof(siz));
        }
        if(siz[st] != -1) return;
        siz[st] = 1;
        for(int i=0;i<mlen;i++){
            if(nex[st][i] != -1){
                initDfs(nex[st][i]);
                siz[st] += siz[nex[st][i]];
            }
        }
    }
    void dfs(int x,int st=-1,int len = 0){
        if(st == -1) st = root;
        if(x <= 1){
            tem[len] = 0;
            printf("%s\n",tem);
            return;
        }
        x--;
        for(int i=0;i<mlen;i++){
            int p = nex[st][i];
            if(p != -1){
                if(x > siz[p]) x -= siz[p];
                else{
                    tem[len] = 'a' + i;
                    dfs(x,p,len+1);
                    return;
                }
            }
        }
    }
}SAM;

char arr[maxn];

int main(){
    scanf("%s",arr);
    SAM.build(arr);
    SAM.initDfs();
    int T;
    scanf("%d",&T);
    int k;
    while(T-- && ~scanf("%d",&k)){
        SAM.dfs(k+1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值