zoukankan      html  css  js  c++  java
  • 【BZOJ3998】弦论 [SAM]

    弦论

    Time Limit: 10 Sec  Memory Limit: 256 MB
    [Submit][Status][Discuss]

    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

    Solution

      首先我们先构造一个后缀自动机,然后分类讨论:

      1. 如果T=0,点权为1。为什么呢?一个点有一个Right集合,一个Right集合可以表达多个子串 ,然后我们一个点 -> 另外一个点 其实不止一条边,我们每条边涵盖了一个信息,意味着 这个点->(走这条边)->到达了下一个点 通过这条边得到的那个新子串,而这多个新子串构成了一个 新的点。所以一条合法的路径,就表达了一个子串

      2. 如果T=1,点权为Right集合大小。Right集合是结束位置的合集,那么Right集合大小就表示这条路径表达的这个子串出现了多少次。

    Code

      1 #include<iostream>  
      2 #include<string>  
      3 #include<algorithm>  
      4 #include<cstdio>  
      5 #include<cstring>  
      6 #include<cstdlib>  
      7 #include<cmath>
      8 using namespace std;
      9 typedef long long s64;
     10 
     11 const int ONE = 2e6+5;
     12 
     13 int n,T,k;
     14 char ch[500005];
     15 
     16 inline int get()
     17 {
     18         int res=1,Q=1;  char c;
     19         while( (c=getchar())<48 || c>57)
     20         if(c=='-')Q=-1;
     21         if(Q) res=c-48; 
     22         while((c=getchar())>=48 && c<=57) 
     23         res=res*10+c-48;
     24         return res*Q; 
     25 }
     26 
     27 struct SAM
     28 {
     29         int v[500005], q[ONE], num[ONE], size[ONE];
     30         int a[ONE][28], len[ONE], fa[ONE], New;
     31         int last, cnt;
     32         
     33         SAM() {last = cnt = 1;}
     34         void Add(int c)
     35         {
     36             int x=last, New=last=++cnt;
     37             len[New] = len[x] + 1;
     38             num[New] = 1;
     39             while(x && !a[x][c]) a[x][c] = New, x = fa[x];
     40             if(!x) {fa[New] = 1; return;}
     41             
     42             int q = a[x][c];
     43             if(len[x] + 1 == len[q]) fa[New] = q;
     44             else
     45             {
     46                 int Nq = ++cnt; len[Nq] = len[x] + 1;
     47                 memcpy(a[Nq], a[q], sizeof(a[q]));
     48                 fa[Nq] = fa[q];
     49                 fa[New] = fa[q] = Nq;
     50                 while(a[x][c] == q) a[x][c] = Nq, x = fa[x];
     51             }
     52         }
     53         
     54         void Update()
     55         {
     56             for(int i=1;i<=cnt;i++) v[len[i]]++;
     57             for(int i=1;i<=n;i++) v[i] += v[i-1];
     58             for(int i=cnt;i>=1;i--) q[v[len[i]]--] = i;
     59             
     60             
     61             for(int i=cnt; i>=1; i--)
     62             {
     63                 int x = q[i];
     64                 if(!T) num[x] = 1; else num[fa[x]] += num[x];    
     65             }
     66             num[1] = 0;
     67             
     68             for(int i=cnt; i>=1; i--)
     69             {
     70                 int x = q[i];
     71                 size[x] = num[x];
     72                 for(int j=1; j<=26; j++)
     73                     size[x] += size[a[x][j]];
     74             }
     75         }
     76         
     77         void Dfs(int u,int k)
     78         {
     79             if(k <= num[u]) return;
     80             k -= num[u];
     81             for(int j=1; j<=26; j++)
     82             if(a[u][j])
     83             {
     84                 if(k > size[a[u][j]]) k -= size[a[u][j]];
     85                 else
     86                 {
     87                     printf("%c",j+'a'-1);
     88                     Dfs(a[u][j], k);
     89                     return;
     90                 }
     91             }
     92         }
     93 }S;
     94 
     95 int main()
     96 {
     97         scanf("%s",ch+1); n = strlen(ch+1);
     98         T = get();    k = get();
     99         for(int i=1;i<=n;i++) S.Add(ch[i]-'a'+1);
    100         
    101         S.Update();
    102         
    103         if(k > S.size[1]) printf("-1");
    104         else S.Dfs(1, k);
    105     
    106 }
    View Code
  • 相关阅读:
    FTP协议操作
    [转贴]SQL2005数据类型
    传智博客学习0512
    20120515传智学习
    20120516分析三层中的null的处理
    20120520晚
    你懂不懂我不知道,反正我是晕了
    20120509小记
    javascript 循环语句 while、dowhile、forin、for用法区别
    C#的一些学习方法
  • 原文地址:https://www.cnblogs.com/BearChild/p/6841659.html
Copyright © 2011-2022 走看看