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# 与 winform 界面开发
    文件大小的友好输出及其 Python 实现
    bookhub -- 扁平化本地电子书管理与分享工具
    阶段性放弃 wxPython 前的总结
    数据挖掘环境下的个人信息安全
    精益阅读 -- 科技图书的阅读过程管理工具
    wxPython Modal Dialog 模式对话框
    wxPython 基本框架与运行原理 -- App 与 Frame
    JAVA向,二叉查找树
    线性表实践-选票算法
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8125287.html
Copyright © 2011-2022 走看看