zoukankan      html  css  js  c++  java
  • BZOJ3998 TJOI2015 弦论 【后缀自动机】【贪心】

    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


    思路

    看这道题是处理K小字串,果断上后缀自动机啊
    然后考虑怎么统计答案
    如果T是0,那么可以每一个节点的大小是1,否则大小是right集合大小
    然后toposort之后反向DP出经过这条转移边可以有多少种字串
    然后就可以直接贪心了


    toposort的数组也要开串长两倍啊啊啊


    #include<bits/stdc++.h>
    using namespace std;
    #define fu(a,b,c) for(int a=b;a<=c;++a)
    #define fd(a,b,c) for(int a=b;a>=c;--a)
    const int CHARSET_SIZE=26;
    #define N 500010
    struct Node{
      int ch[CHARSET_SIZE],prt;
      int maxl,right;
      Node(int maxl=0,int right=0):ch(),prt(0),maxl(maxl),right(right){}
    }t[N<<1];
    int root,last,cur;
    int topo[N<<1],buc[N];
    int newnode(int maxl=0,int right=0){t[++cur]=Node(maxl,right);return cur;}
    void init(){cur=0;root=last=newnode();}
    void extend(int c){
      int u=newnode(t[last].maxl+1,1),v=last;
      for(;v&&!t[v].ch[c];v=t[v].prt)t[v].ch[c]=u;
      if(!v){t[u].prt=root;}
      else if(t[t[v].ch[c]].maxl==t[v].maxl+1){
        t[u].prt=t[v].ch[c];
      }else{
        int n=newnode(t[v].maxl+1,0),o=t[v].ch[c];
        memcpy(t[n].ch,t[o].ch,sizeof(t[o].ch));
        t[n].prt=t[o].prt;
        t[o].prt=t[u].prt=n;
        for(;v&&t[v].ch[c]==o;v=t[v].prt)t[v].ch[c]=n;
      }
      last=u;
    }
    void toposort(){
      int maxv=0;
      fu(i,1,cur){
        ++buc[t[i].maxl];
        maxv=max(maxv,t[i].maxl);
      }
      fu(i,1,maxv)buc[i]+=buc[i-1];
      fu(i,1,cur)topo[buc[t[i].maxl]--]=i;
      fu(i,1,maxv)buc[i]=0;
    }
    void cal_right(){
      toposort();
      fd(i,cur,1){
        int p=topo[i];
        t[t[p].prt].right+=t[p].right;
      }
    }
    char c[N],ans[N];
    int T,K,dp[N<<1];
    int main(){
      scanf("%s",c+1);
      scanf("%d%d",&T,&K);
      int len=strlen(c+1);
      init();
      fu(i,1,len)extend(c[i]-'a');
      cal_right();
      fu(i,2,cur)dp[i]=T?t[i].right:1;
      fd(i,cur,1)
        fu(j,0,25)
          dp[topo[i]]+=dp[t[topo[i]].ch[j]];
      if(K>dp[1]){printf("-1");return 0;}
      int now=1,siz=0;
      while(1){
        int tmp=T?t[now].right:1;
        if(now==1)tmp=0;
        if(K<=tmp)break;
        K-=tmp;
        fu(i,0,25)if(t[now].ch[i]){
          int v=t[now].ch[i];
          if(dp[v]>=K){ans[++siz]=i+'a';now=v;break;}
          else K-=dp[v];
        }
      }
      fu(i,1,siz)printf("%c",ans[i]);
      return 0;
    }
    
  • 相关阅读:
    Leetcode(680) ;验证回文字符串 Ⅱ
    mysql常用操作语句
    组合索引问题
    php生成一维码以及保存-转载
    php后台实现页面跳转的方法-转载
    php操作表格(写)
    虚拟机复制后上网冲突的问题
    centos下安装nginx(转载)
    虚拟机与宿主机可以互相ping通,但是外网不能
    防火墙设置:虚拟机ping不通主机,但是主机可以ping通虚拟机(转载)
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9696041.html
Copyright © 2011-2022 走看看