• SPOJ


    感觉后缀自动机好难啊,比后缀数组难多了...看了好几天勉强懂了一丢丢

    学习博客:

    洛谷某大佬

    HihoCoder

    题目传送门:https://www.spoj.com/problems/SUBLEX/en/

    题意:给你一个字符串,然后是q次查询,每次输出第i小的字符串。

    题解:先构造出后缀自动机,然后对每个节点预处理出从这个节点可以到达多少个不同的子串,然后沿着SAM一路查找下去并更新。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 const int maxn=2e6+10;
      5 
      6 struct state
      7 {
      8     int mxlen,link;
      9     int cnt;
     10     int nt[26];
     11 }st[maxn<<1];
     12 
     13 int sz,last;
     14 char s[maxn];
     15 
     16 inline void sam_init()
     17 {
     18    st[0].mxlen=0;
     19    st[0].link=-1;
     20    sz=1;
     21    last=0;
     22 }
     23 
     24 inline void sam_extend(int c)
     25 {
     26     c-='a';
     27     int cur=sz++;
     28     st[cur].mxlen=st[last].mxlen+1;
     29     st[cur].cnt=1;
     30     int p=last;
     31     while(p!=-1&&!st[p].nt[c]){
     32         st[p].nt[c]=cur;
     33         p=st[p].link;
     34     }
     35     if(p==-1) st[cur].link=0;
     36     else{
     37         int q=st[p].nt[c];
     38         if(st[p].mxlen+1==st[q].mxlen) st[cur].link=q;
     39         else{
     40             int clone=sz++;
     41             st[clone].mxlen=st[p].mxlen+1;
     42             memcpy(st[clone].nt,st[q].nt,sizeof(st[q].nt));
     43             st[clone].link=st[q].link;
     44             while(p!=-1&&st[p].nt[c]==q){
     45                 st[p].nt[c]=clone;
     46                 p=st[p].link;
     47             }
     48             st[q].link=st[cur].link=clone;
     49         }
     50     }
     51     last=cur;
     52 }
     53 
     54 int b[maxn],c[maxn];
     55 
     56 void build()        //这个难道不是基排吗,为啥看好多博客写拓扑排序,,,
     57 {
     58     int len=strlen(s+1);
     59     for(int i=1;i<=len;i++) sam_extend(s[i]);
     60     for(int i=1;i<=sz;i++) c[st[i].mxlen]++;
     61     for(int i=1;i<=sz;i++) c[i]+=c[i-1];
     62     for(int i=1;i<=sz;i++) b[c[st[i].mxlen]--]=i;
     63     for(int i=sz;i>=1;i--){
     64         st[b[i]].cnt=1;
     65         for(int j=0;j<26;j++)
     66             st[b[i]].cnt+=st[st[b[i]].nt[j]].cnt;     //st[].cnt记录当前节点不同子串个数
     67     }
     68 }
     69 
     70 void query(int k)
     71 {
     72     int p=0;
     73     while(k){
     74         for(int i=0;i<26;i++){
     75             if(st[p].nt[i]){
     76                 if(k>st[st[p].nt[i]].cnt) k-=st[st[p].nt[i]].cnt;
     77                 else {
     78                     char ch=i+'a';
     79                     cout<<ch;
     80                     p=st[p].nt[i];
     81                     k--;
     82                     break;
     83                 }
     84             }
     85         }
     86     }
     87 }
     88 
     89 int main()
     90 {
     91     ios::sync_with_stdio(false);
     92     cin.tie(0);
     93     cout.tie(0);
     94     cin>>s+1;
     95     sam_init();
     96     build();
     97     int m;
     98     cin>>m;
     99     while(m--){
    100         int n;
    101         cin>>n;
    102         query(n);
    103         cout<<endl;
    104     }
    105     return 0;
    106 }

    有一个地方我一直没搞清楚,这两种写法不一样吗?一种是父亲加上他,一种是它加儿子,最后结果应该是一样的吧...但是第一种写法是错的。

    1     for(int i=sz;i>=1;i--) st[i].cnt=1;
    2     for(int i=sz;i>=1;i--) st[st[b[i]].link].cnt+=st[b[i]].cnt;
    1   for(int i=sz;i>=1;i--){
    2         st[b[i]].cnt=1;
    3         for(int j=0;j<26;j++)
    4             st[b[i]].cnt+=st[st[b[i]].nt[j]].cnt;
    5     }
  • 相关阅读:
    <<Rust程序设计语言>>个人版(4: 所有权)
    《逻辑学入门》笔记(45-66)
    《逻辑学入门》笔记(23-44)
    <<Rust程序设计语言>>个人版(3.3: 函数/3.4: 注释/3.5: 控制流)
    <<Rust程序设计语言>>个人版(1: 入门/2: 编写猜谜游戏)
    网站如何保护用户的密码
    在 Gin 项目中使用 WebSocket
    《逻辑学入门》笔记(1-22)
    浅谈双重认证逻辑
    某大型网络安全活动中遇到的钓鱼邮件
  • 原文地址:https://www.cnblogs.com/lilibuxiangtle/p/12798113.html
Copyright © 2020-2023  润新知