码迷,mamicode.com
首页 > 其他好文 > 详细

Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

时间:2019-05-22 19:13:27      阅读:77      评论:0      收藏:0      [点我收藏+]

标签:def   否则   ini   mes   max   直接   next   sub   list   

Lexicographical Substrings Search

\[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \]

题意

给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串。

思路

先对给出的字符串构建后缀自动机,因为后缀自动机上从根节点走到任意节点都是原串的一个子串,所以我们可以 \(dfs\) 求出节点 \(i\) 往后存在多少个子串。
对于查询第 \(k\) 小的子串时,在用一个 \(dfs\) 来求,对于当前节点\(u\), 从\(1-26\) 枚举下一步的方案 \(v\),如果从 \(v\) 往后的子串比 \(k\) 少,那么不用往下走,直接 \(k-=cnt[v]\)。否则往下走一步,让 \(k--\)。如此一直走到 \(k=0\) 为止。

/***************************************************************
    > File Name    : a.cpp
    > Author       : Jiaaaaaaaqi
    > Created Time : 2019年05月22日 星期三 17时06分12秒
 ***************************************************************/

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

struct SAM {
    struct Node{
        int next[27];
        int fa, len;
        void init() {
            mes(next, 0);
            len = fa = 0;
        }
    } node[maxn<<1];
    int sz, last;
    int cnt[maxn<<1];
    void init() {
        sz = last = 1;
        node[sz].init();
        mes(cnt, 0);
    }
    void insert(int k) {
        int p = last, np = last = ++sz;
        node[np].init();
        node[np].len = node[p].len+1;
        for(; p&&!node[p].next[k]; p=node[p].fa)
            node[p].next[k] = np;
        if(p==0) {
            node[np].fa = 1;
        } else {
            int q = node[p].next[k];
            if(node[q].len == node[p].len + 1) {
                node[np].fa = q;
            } else {
                int nq = ++sz;
                node[nq] = node[q];
                node[nq].len = node[p].len + 1;
                node[np].fa = node[q].fa = nq;
                for(; p&&node[p].next[k]==q; p=node[p].fa)
                    node[p].next[k] = nq;
            }
        }
    }
    void dfs(int u) {
        if(cnt[u])  return ;
        cnt[u] = 1;
        for(int i=1; i<=26; i++) {
            int v = node[u].next[i];
            if(v) {
                dfs(v);
                cnt[u] += cnt[v];
            }
        }
    }
    char ss[maxn];
    void find(int u, int k, int len) {
        if(k==0) {
            ss[len] = '\0';
            printf("%s\n", ss+1);
            return ;
        }
        for(int i=1; i<=26; i++) {
            int v = node[u].next[i];
            if(v==0)    continue;
            if(cnt[v] < k)  k -= cnt[v];
            else {
                k--;
                ss[len] = 'a'+i-1;
                find(v, k, len+1);
                return ;
            }
        }
    }
    void solve(int k) {
        find(1, k, 1);
    }
} sam;
char s[maxn];

int main() {
    sam.init();
    scanf("%s", s+1);
    int len = strlen(s+1);
    for(int i=1; i<=len; i++) {
        sam.insert(s[i]-'a'+1);
    }
    sam.dfs(1);
    // for(int i=2; i<=sam.sz; i++) {
    //     printf("cnt[%d] = %d\n", i, sam.cnt[i]);
    // }
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &m);
        sam.solve(m);
    }
    return 0;
}

Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

标签:def   否则   ini   mes   max   直接   next   sub   list   

原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/10907687.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!