zoukankan      html  css  js  c++  java
  • 【BZOJ】3998: [TJOI2015]弦论

    【题意】给定长度为n的小写字母字符串S,求第k小子串。n<=5*10^5。

    给定T,T=0时不同位置的相同子串算一个,T=1时算多个。

    【算法】后缀自动机

    【题解】对S建立SAM,T=0则每个节点算1次,T=1则每个节点算Right次,那么第k小就是dfs到恰好前k个的位置就是答案(SAM自带字典序)。

    DFS前,我们需要每个点的Right数组大小,每个子树(trans边)的Right数组之和。

    首先使所有前缀开端节点Right=1(即每次的np),然后对所有点按len进行基数排序从而保证拓扑序,然后从后往前统计。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=1000010;
    struct tree{int len,fa, t[30];}t[maxn];
    int n,last,T,k,tot,right[maxn],sum[maxn],root,w[maxn],b[maxn];
    char s[maxn];
    void insert(int c){
        int np=++tot;
        t[np].len=t[last].len+1;
        right[np]=1;
        int x=last;
        while(x&&!t[x].t[c])t[x].t[c]=np,x=t[x].fa;
        last=np;
        if(!x)t[np].fa=root;else{
            int y=t[x].t[c];
            if(t[y].len==t[x].len+1)t[np].fa=y;else{
                int nq=++tot;
                t[nq]=t[y];
                t[nq].len=t[x].len+1;
                t[nq].fa=t[y].fa;t[y].fa=t[np].fa=nq;
                while(x&&t[x].t[c]==y)t[x].t[c]=nq,x=t[x].fa;
            }
        }
    }
    void dfs(int x){
        if(k<=right[x])return;
        k-=right[x];
        for(int i=0;i<26;i++)if(t[x].t[i]){
            int y=t[x].t[i];
            if(k>sum[y])k-=sum[y];else{
                putchar(i+'a');
                dfs(y);
                return;
            }
        }
    }
    int main(){
        scanf("%s",s+1);n=strlen(s+1);
        root=tot=last=1;
        for(int i=1;i<=n;i++)insert(s[i]-'a');
        scanf("%d%d",&T,&k);
        for(int i=1;i<=tot;i++)w[t[i].len]++;
        for(int i=1;i<=n;i++)w[i]+=w[i-1];
        for(int i=1;i<=tot;i++)b[w[t[i].len]--]=i;
        for(int j=tot;j>=2;j--){
            int i=b[j];
            if(T)right[t[i].fa]+=right[i];else right[i]=1;
        }
        right[root]=0;
        for(int o=tot;o>=1;o--){
            int i=b[o];sum[i]=right[i];
            for(int j=0;j<26;j++)if(t[i].t[j])sum[i]+=sum[t[i].t[j]];
        }
        if(k>sum[root])printf("-1");else dfs(root);
        return 0;
    }
    View Code
  • 相关阅读:
    制作计算器的代码(C#)
    Oracle如何实现创建数据库、备份数据库及数据导出导入操作
    XmlDocument类
    Android强大的开源库与系统架构工具
    IO
    胎压监测设备
    福施福、爱乐维、玛特纳各成分比较(已换算成同一单位)
    用车不容忽视的细节
    汽车必备车饰和常用物品
    j2ee指导型框架或示例
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8125287.html
Copyright © 2011-2022 走看看