• 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )


    3998: [TJOI2015]弦论

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 2627  Solved: 881

    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

    【分析】

      建SAM,然后跑。

      right数组要按照拓扑序来求啊!!!!

      然后累计儿子的和的时候也要用拓扑序。

      具体拓扑序:

      

    for(int i=1;i<=tot;i++) v[t[i].step]++;
    for(int i=1;i<=tot;i++) v[i]+=v[i-1];
    for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
    

      类似后缀数组那里的了。

      T=0,就right一开始都为1;T=1,就用right数组。

      空串算一个串,一开始k++。

      当然后缀数组也是可以的。

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 #define Maxn 500010
      8 
      9 struct node
     10 {
     11     int pre,last,son[30],step;
     12 }t[Maxn*2];
     13 int rt[Maxn*2],sm0[2*Maxn],sm1[2*Maxn];
     14 int v[2*Maxn],q[2*Maxn];
     15 
     16 struct sam
     17 {
     18     int last,tot;
     19     void extend(int k)
     20     {
     21         int np=++tot,p=last;
     22         t[np].step=t[last].step+1;
     23         rt[np]=1;
     24         while(p&&!t[p].son[k])
     25         {
     26             t[p].son[k]=np;
     27             p=t[p].pre;
     28         }
     29         if(!p) t[np].pre=1;
     30         else
     31         {
     32             int q=t[p].son[k];
     33             if(t[q].step==t[p].step+1) t[np].pre=q;
     34             else
     35             {
     36                 int nq=++tot;
     37                 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
     38                 t[nq].step=t[p].step+1;
     39                 t[nq].pre=t[q].pre;
     40                 t[q].pre=t[np].pre=nq;
     41                 while(p&&t[p].son[k]==q)
     42                 {
     43                     t[p].son[k]=nq;
     44                     p=t[p].pre;
     45                 }
     46             }
     47         }
     48         last=np;
     49     }
     50     void init()
     51     {
     52         for(int i=1;i<=tot;i++) v[t[i].step]++;
     53         for(int i=1;i<=tot;i++) v[i]+=v[i-1];
     54         for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
     55         
     56         // for(int i=1;i<=tot;i++) rt[i]=1;
     57         // for(int i=tot;i>=1;i--) rt[t[i].pre]+=rt[i];
     58         // rt[1]=1;
     59         for(int i=tot;i>=1;i--)
     60         {
     61             int nw=q[i];
     62             rt[t[nw].pre]+=rt[nw];
     63         }rt[1]=1;
     64         
     65         for(int i=tot;i>=1;i--)
     66         {
     67             int nw=q[i];
     68             sm0[nw]=1;sm1[nw]=rt[nw];
     69             for(int j=1;j<=26;j++) if(t[nw].son[j])
     70             {
     71                 sm0[nw]+=sm0[t[nw].son[j]];
     72                 sm1[nw]+=sm1[t[nw].son[j]];
     73             }
     74         }
     75     }
     76     void ffind(int opt,int k)
     77     {
     78         int sm,nw=1;
     79         k++;
     80         while(1)
     81         {
     82             sm=opt?rt[nw]:1;
     83             for(int i=1;i<=26;i++) if(t[nw].son[i])
     84             {
     85                 int ss=sm;
     86                 if(!opt) sm+=sm0[t[nw].son[i]];
     87                 else sm+=sm1[t[nw].son[i]];
     88                 if(sm>=k) {k-=ss;printf("%c",'a'+i-1);nw=t[nw].son[i];break;}
     89             }
     90             if(!opt&&k==1) break;
     91             if(opt&&k<=rt[nw]) break;
     92         }
     93         printf("
    ");
     94     }
     95 }sam;
     96 
     97 char s[Maxn];
     98 
     99 int main()
    100 {
    101     scanf("%s",s);
    102     int l=strlen(s);
    103     sam.last=sam.tot=1;
    104     for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1);
    105     sam.init();
    106     int opt,k;
    107     scanf("%d%d",&opt,&k);
    108     if(!opt&&k+1>sm0[1]) printf("-1
    ");
    109     else if(opt&&k+rt[1]>sm1[1]) printf("-1
    ");
    110     else sam.ffind(opt,k);
    111     return 0;
    112 }
    View Code

    2017-04-17 13:59:36

      

  • 相关阅读:
    如何将用户中的表拷贝到其他用户当中
    Java 网络编程
    oracle 10g 在win7下安装,提示程序异常终止,发生未知错误
    &运算<<移位运算
    Delegate and Protocol
    Property
    [转载]OpenCV2.2.0win32vs2010在VS2010下的安装
    Adobe_Premiere_CS4快捷键大全
    vs2008 + OpenCV2.1.0win32vs2008安装
    Xcode 3.2.5免证书开发调试[转]
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6722630.html
Copyright © 2020-2023  润新知