zoukankan      html  css  js  c++  java
  • BZOJ 3998 [TJOI2015]弦论 (后缀自动机)

    题目大意:

    给你一个字符串,求字典序第$k$小的串是什么

    先建出$sam$和$parent$树

    在$trs$图中,从根走向节点x的每一条路径都是x能代表的一个字符串

    $parent$树以 某个节点为根的子树内$endpos$节点的数量,表示这个节点 能代表的所有字符串 正序作为后缀在所有前缀串中出现的次数

    利用这个性质,我们在$trs$图中反向拓扑,就能累加出以某个节点x代表的某个字符串为前缀的子串总数量

    因为从一个节点$x$沿一条正向边$trs[x][i]$走向一个节点$y$,我们能表示的字符串就是在$x$原来表示的某个字符串$S$之后添加一个字符$i$,是正序的

    而反向拓扑是统计$S$后面能接的串$ixxx$的总数量

    最后在$trs$图上26分即可

      1 #include <vector>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #define N1 505000
      6 #define S1 (N1<<1)
      7 #define ll long long
      8 #define uint unsigned int
      9 #define rint register int 
     10 #define il inline 
     11 #define inf 0x3f3f3f3f
     12 #define idx(X) (X-'a')
     13 using namespace std;
     14 
     15 int gint()
     16 {
     17     int ret=0,fh=1;char c=getchar();
     18     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
     19     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
     20     return ret*fh;
     21 }
     22 
     23 int T,K,n,m,len,cte;
     24 char str[N1];
     25 
     26 namespace SAM{
     27 int trs[S1][26],pre[S1],dep[S1],ed[S1],la,tot;
     28 ll sz[S1],sum[S1];
     29 void init(){tot=la=1;}
     30 void Build_SAM(int x)
     31 {
     32     int p,q,np,nq;
     33     np=++tot,p=la,la=np;
     34     dep[np]=dep[p]+1,ed[np]=1;
     35     for(;p&&!trs[p][x];p=pre[p]) trs[p][x]=np;
     36     if(!p) pre[np]=1;
     37     else{
     38         q=trs[p][x];
     39         if(dep[q]==dep[p]+1) pre[np]=q;
     40         else{
     41             pre[nq=++tot]=pre[q];
     42             pre[np]=pre[q]=nq;
     43             dep[nq]=dep[p]+1;
     44             memcpy(trs[nq],trs[q],sizeof(trs[q]));
     45             for(;p&&trs[p][x]==q;p=pre[p]) trs[p][x]=nq; 
     46         }
     47     }
     48 }
     49 bool cmp(int x,int y){return x<y;}
     50 
     51 int ret[N1],tp;
     52 int hs[S1],que[S1];
     53 void solve()
     54 {
     55     init();
     56     for(int i=1;i<=len;i++)
     57         Build_SAM(idx(str[i]));
     58     for(int i=2;i<=tot;i++)
     59         hs[dep[i]]++;
     60     for(int i=1;i<=len;i++)
     61         hs[i]+=hs[i-1];
     62     for(int i=1;i<=tot;i++)
     63         que[hs[dep[i]]--]=i;
     64     int x;
     65     for(int i=tot-1;i>=1;i--)
     66     {
     67         x=que[i];
     68         sz[x]+=ed[x]?1:0;
     69         if(!T) sz[x]=1;
     70         else sz[pre[x]]+=sz[x];
     71     }
     72     sz[1]=0;
     73     for(int i=tot-1;i>=0;i--)
     74     {
     75         x=que[i];
     76         sum[x]+=sz[x];
     77         for(int j=0;j<26;j++)
     78             sum[x]+=sum[trs[x][j]];
     79     }
     80     x=1;
     81     if(K>sum[1]){printf("-1
    ");return;}
     82     while(1)
     83     {
     84         if(K<=sz[x]) {break;}
     85         K-=sz[x];
     86         for(int i=0;i<26;i++)
     87         {
     88             if(K>sum[trs[x][i]]){
     89                 K-=sum[trs[x][i]];
     90             }else{
     91                 ret[++tp]=i;
     92                 x=trs[x][i];
     93                 break;
     94             }
     95         }
     96     }
     97     for(int i=1;i<=tp;i++)
     98         printf("%c",ret[i]+'a');
     99     puts("");
    100 }
    101 };
    102 
    103 int main()
    104 {
    105     //freopen("t2.in","r",stdin);
    106     scanf("%s",str+1);
    107     len=strlen(str+1);
    108     scanf("%d%d",&T,&K);
    109     SAM::solve();
    110     return 0;
    111 }
  • 相关阅读:
    Linux oracle操作
    Job
    Oracle创建表空间和用户并分配权限
    Oracle赋予用户查询另一个用户所有表的权限
    plsql中文乱码解决方案
    PLSQL创建Oracle定时任务,定时执行存储过程
    fcntl函数参数F_GETPIPE_SZ、F_SETPIPE_SZ报错引出的关于linux-specific头文件的使用方法
    从Windows Server 2008 迁移mantis到CentOS 6.8
    从Windows Server 2008 迁移VisualSVN到CentOS 6.8
    CentOS 6.8上开启NFS服务给不同用户使用的曲线设置方法
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10096962.html
Copyright © 2011-2022 走看看