zoukankan      html  css  js  c++  java
  • SPOJ SUBLEX 求第k小子串

     题目大意:

    对于一个给定字符串,找到其所有不同的子串中排第k小的子串

    先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N]

    对于每个节点记录一个sc值,表示当前节点往下走可以得到不同的字符串的个数

    然后从后往前,每次到达一个节点,当前节点sc赋1,然后每个可以往下走的son节点,都把这个son上的sc加到当前节点上即可

    接下来得到一个排名,从root开始走,从a~z循环,通过sc正确的找到下一个进入的节点

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 #define N 90005
     7 
     8 struct SamNode{
     9     int l , sc;
    10     SamNode *son[26] , *f;
    11 }sam[N<<1] , *root , *last , *b[N<<1];
    12 
    13 int cnt , num[N] , n , k;
    14 char s[N];
    15 void add(int x)
    16 {
    17     SamNode *p = &sam[++cnt] , *jp = last;
    18     p->l = jp->l+1;
    19     last = p;
    20     for(; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
    21     if(!jp) p->f = root;
    22     else{
    23         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
    24         else{
    25             SamNode *r = &sam[++cnt] , *q = jp->son[x];
    26             *r = *q; r->l = jp->l+1;
    27             p->f = q->f = r;
    28             for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x] = r;
    29         }
    30     }
    31 }
    32 
    33 void build()
    34 {
    35     int len = strlen(s);
    36     for(int i=0 ; i<len ; i++) add(s[i]-'a');
    37     for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
    38     for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
    39     for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]] = &sam[i];
    40 
    41     for(int i=cnt ; i>=1 ; i--){
    42         b[i]->sc=1;
    43         for(int j=0 ; j<26 ; j++){
    44             if(b[i]->son[j])
    45                 b[i]->sc+=b[i]->son[j]->sc;
    46         }
    47     }
    48 }
    49 
    50 void solve()
    51 {
    52     scanf("%d" , &n);
    53     char tmp[N];
    54     int val , t;//t表示tmp中的位数
    55     while(n--){
    56         scanf("%d" , &k);
    57         SamNode *cur = root;
    58         val = 0 , t=0;
    59         while(val<k){
    60             for(int i=0 ; i<26 ; i++){
    61                 if(cur->son[i]){
    62                     if(val+cur->son[i]->sc<k) val+=cur->son[i]->sc;
    63                     else{
    64                         val++;
    65                         tmp[t++] = i+'a';
    66                         cur = cur->son[i];
    67                         break;
    68                     }
    69                 }
    70             }
    71         }
    72         tmp[t]='';
    73         printf("%s
    " , tmp);
    74     }
    75 }
    76 
    77 int main()
    78 {
    79   //  freopen("a.in" , "r" , stdin);
    80     scanf("%s" , s);
    81     root = last = &sam[cnt=0];
    82     build();
    83     solve();
    84     return 0;
    85 }
  • 相关阅读:
    第一章:Android系统的编译和移植实例读书笔记
    第二章:Android系统与嵌入式开发读书笔记
    第三章:Android移植平台工具介绍读书笔记
    第十章 嵌入式Linux的调试技术
    第九章 硬件抽象层:HAL
    第八章 让开发板发出声音:蜂鸣器驱动
    第七章 LED将为我闪烁:控制发光二极管
    第六章 第一个Linux驱动程序:统计单词个数
    第五章 搭建S3C6410开发板的测试环境
    第四章 源代码的下载和编译
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4598531.html
Copyright © 2011-2022 走看看