【SPOJ7258】Lexicographical Substring Search-后缀自动机+拓补序递推
来源:互联网 发布:网络报纸取代传统报纸 编辑:程序博客网 时间:2024/05/19 05:33
测试地址:Lexicographical Substring Search
题目大意:给定一个字符串,有Q个询问,每个询问字符串中字典序第Ki小的本质不同的子串。
做法:这几天学习了后缀自动机(Suffix Automaton,SAM),个人感觉除了clj的原论文,写得最好的就是这个,我就是看着这个学会后缀自动机的。里面最后讲的一道例题就是这道题,首先对字符串构建后缀自动机,然后对于每个点维护一个值s,指从这个点出发最多能找到的子串数,显然我们可以按原图的反向拓补序依次求出每一个点的s,所以我们可以用类似记忆化搜索的方法递推,搜索到没算过的点继续往下算,算过的就直接累加,当然从一个点出发能找到的子串也包括这个点自身,所以回来时记得+1。然后对于每个询问,从起始节点开始,按照字典序从小到大扫过每个儿子,如果K大于当前儿子能找到的子串数,则将K减去这个数,然后找下一个儿子,直到找到一个儿子使得从它出发能找到的子串数≥K,就输出这个儿子的字母,然后从这个儿子往下寻找。因为从一个点出发能找到的子串也包括这个点自身,所以每走过一个点,都要把K减去1,当K等于0的时候就结束。这样,总的时间复杂度就是O(NQ),可以通过。
我犯二的地方:第一次写想错了,把最后一个插入的点当成最后一个可以接受后缀的点......显然错了,要分清楚这两个概念。
以下是本人代码:
#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;char s[100010];int n,q,tot=0,in[200010]={0},last=0;struct SAMnode{ int pre,ch[30],step,s;}nd[200010];bool vis[200010]={0};void extend(int c){ int p=last,q,np=++tot,nq; nd[np].step=nd[p].step+1; for(int i=0;i<=25;i++) nd[np].ch[i]=-1; while(nd[p].ch[c]==-1&&p!=-1) { nd[p].ch[c]=np;p=nd[p].pre; } if (p!=-1) { q=nd[p].ch[c];if (nd[q].step==nd[p].step+1){ nd[np].pre=q;}else{ nq=++tot; nd[nq].pre=nd[q].pre; for(int i=0;i<=25;i++) nd[nq].ch[i]=nd[q].ch[i]; nd[nq].step=nd[p].step+1; nd[nq].s=1; nd[q].pre=nq,nd[np].pre=nq; while(p!=-1&&nd[p].ch[c]==q) { nd[p].ch[c]=nq;p=nd[p].pre; }} } else nd[np].pre=0; nd[np].s=1; last=np;}void calc_s(int v){ for(int i=0;i<=25;i++) if (nd[v].ch[i]!=-1){ if (!vis[nd[v].ch[i]]) calc_s(nd[v].ch[i]); nd[v].s+=nd[nd[v].ch[i]].s;} vis[v]=1;}void build(){ nd[0].pre=-1;nd[0].s=0;nd[0].step=0; for(int i=0;i<=25;i++) nd[0].ch[i]=-1; for(int i=0;i<n;i++) extend(s[i]-'a'); for(int i=0;i<=tot;i++) if (nd[i].step==n) {vis[i]=1;break;} calc_s(0);}void output(int a){ int v=0; while(a) { for(int i=0;i<=25;i++) if (nd[v].ch[i]!=-1) { if (a>nd[nd[v].ch[i]].s) a-=nd[nd[v].ch[i]].s;else {v=nd[v].ch[i];printf("%c",i+'a');break;} }a--; } if (q) printf("\n");}int main(){ scanf("%s",s); n=strlen(s); build(); scanf("%d",&q); while(q--) { int a;scanf("%d",&a);output(a); } return 0;}
0 0
- 【SPOJ7258】Lexicographical Substring Search-后缀自动机+拓补序递推
- spoj7258 Lexicographical Substring Search(SUBLEX) 后缀自动机
- [spoj7258]Lexicographical Substring Search && 后缀自动机
- spoj7258:Lexicographical Substring Search 后缀自动机
- spoj7258 Lexicographical Substring Search(SUBLEX),后缀自动机
- [SPOJ7258]SUBLEX - Lexicographical Substring Search(后缀自动机)
- spoj7258:Lexicographical Substring Search(后缀自动机+拓扑排序)
- [SPOJ7258]SUBLEX - Lexicographical Substring Search
- spoj 7258 Lexicographical Substring Search (后缀自动机)
- SPOJ Lexicographical Substring Search --后缀自动机
- SPOJ SUBLEX Lexicographical Substring Search 后缀自动机
- 【后缀自动机】[SPOJ SUBLEX]Lexicographical Substring Search
- SPOJ Lexicographical Substring Search 后缀自动机
- spoj 7258 Lexicographical Substring Search(后缀数组 | 后缀自动机)
- spoj 7258 Lexicographical Substring Search (后缀自动机+dp)
- SPOJ 7258 SUBLEX - Lexicographical Substring Search (后缀自动机)
- SPOJ 题目7528 SUBLEX - Lexicographical Substring Search(后缀自动机求排名k的子串)
- SPOJ SUBLEX Lexicographical Substring Search
- cocos2dx lua 为什么显示的内容之后,只有左下角无限增长?
- 最短路径by floyd算法
- nginx编译安装教程
- Dijkstra算法--图的最短路径
- android MotionEvent和TouchSlop触摸处理
- 【SPOJ7258】Lexicographical Substring Search-后缀自动机+拓补序递推
- Centos7 中 python 开发环境准备
- 如何实现按下两次退出键,退出程序
- (2)简单工厂模式
- linux 把cd 命令写在bash shell脚本里不起作用
- 程序清单3-2 InputTest
- Realm For Android
- php curl经典最常用例子
- 知识图谱——机器大脑中的知识库