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

【TJOI2015】【BZOJ3998】弦论

时间:2015-08-30 17:34:40      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:后缀自动机

Description

对于一个给定长度为N的字符串,求它的第K小子串是什么。

Input

第一行是一个仅由小写英文字母构成的字符串S

第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output

输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

Sample Input

aabc

0 3
Sample Output

aab

HINT

N<=5*10^5

T<2

K<=10^9
Source
字典序第k小子串
SAM裸题
张天扬论文有详解
我这个傻逼求right集合的方法错了一直WA…
第二天才调好QAQ

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1000010
using namespace std;
int T,n,k;
char ch[MAXN>>1];
int c[MAXN],od[MAXN];
struct sam
{
    int p,q,np,nq,last,cnt;
    int len[MAXN],a[MAXN][26],fa[MAXN];
    int right[MAXN],sum[MAXN];
    sam()
    {
        last=++cnt;
    }
    inline void insert(int c)
    {
        p=last;np=last=++cnt;len[np]=len[p]+1;len[np]=len[p]+1;right[np]=1;
        while (!a[p][c]&&p) a[p][c]=np,p=fa[p];
        if (!p) fa[np]=1;
        else
        {
            q=a[p][c];
            if (len[q]==len[p]+1)   fa[np]=q;
            else
            {
                nq=++cnt;len[nq]=len[p]+1;
                memcpy(a[nq],a[q],sizeof(a[q]));
                fa[nq]=fa[q];fa[q]=fa[np]=nq;
                while (a[p][c]==q)  a[p][c]=nq,p=fa[p];
            }
        }
    }
    inline void init()//求出right集合和可到达状态总数sum 
    {
        for (int i=1;i<=cnt;i++)    c[len[i]]++;
        int L=strlen(ch);
        for (int i=1;i<=L;i++)  c[i]+=c[i-1];
        for (int i=cnt;i;i--)   od[c[len[i]]--]=i;
        for (int i=cnt;i;i--)
        {
            int x=od[i];
            if (T)  right[fa[x]]+=right[x];
            else    right[x]=1;
        }
        right[1]=0;
        for (int i=cnt;i;i--)
        {
            int x=od[i];
            sum[x]=right[x];
            for (int j=0;j<26;j++)  sum[x]+=sum[a[x][j]];
        }
    }
    inline void dfs(int x,int nowk)
    {
        if (nowk<=right[x]) return;
        nowk-=right[x];
        for (int i=0;i<26;i++)
            if (a[x][i])
            {
                if (nowk<=sum[a[x][i]])
                {
                    putchar(i+‘a‘);
                    dfs(a[x][i],nowk);
                    return;
                }
                nowk-=sum[a[x][i]];
            }
    }
}sam;
int main()
{
    scanf("%s",ch);
    scanf("%d%d",&T,&k);
    int l=strlen(ch);
    for (int i=0;i<l;i++)   sam.insert(ch[i]-‘a‘);
    sam.init();
    if (k>sam.sum[1])   puts("-1");
    else    sam.dfs(1,k);
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

【TJOI2015】【BZOJ3998】弦论

标签:后缀自动机

原文地址:http://blog.csdn.net/creationaugust/article/details/48106079

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