SPOJ SUBLEX Lexicographical Substring Search
2017-09-26 18:07
357 查看
SPOJ SUBLEX Lexicographical Substring Search
SAM,后缀自动机,计数题意
给一个字符串S,将他的所有子串(去重)按字典序排序,给q个询问,问拍第k个子串是谁。思路
后缀自动机的计数问题。后缀自动机每个状态都代表一个或几个字符串。统计每个节点能到达多少个跟他具有相同前缀的字符串。换句话说就是统计每个点通过trans边能到多少个串。方法可以dfs,也可以基排。基排就是处理出拓扑序后从后往前更新。
处理好subamo数组后,查找时尽量走小的边。就获得了最终rank(k)的字符串。
代码
#include <bits/stdc++.h> #define M(a,b) memset(a,b,sizeof(a)) typedef long long LL; using namespace std; const int MAXL=100005; const int MAXS=26; struct SAM { int n, len, st; int maxlen[2*MAXL+10], minlen[2*MAXL+10], trans[2*MAXL+10][MAXS], slink[2*MAXL+10], subamo[2*MAXL+10]; int new_state(int _maxlen, int _minlen, int* _trans, int _slink) { n++; maxlen =_maxlen; minlen =_minlen; subamo =1; for(int i=0; i<MAXS; i++) { if(_trans==NULL) trans [i]=0; else trans [i]=_trans[i]; } slink =_slink; return n; } int add_char(char ch, int u) { int c=ch-'a'; int z=new_state(maxlen[u]+1, -1, NULL, 0); int v=u; while(v!=0&&trans[v][c]==0) { trans[v][c]=z; v=slink[v]; } if(v==0) { minlen[z]=1; slink[z]=1; return z; } int x=trans[v][c]; if(maxlen[v]+1==maxlen[x]) { minlen[z]=maxlen[x]+1; slink[z]=x; return z; } int y=new_state(maxlen[v]+1, -1, trans[x], slink[x]); minlen[x]=maxlen[y]+1; slink[x]=y; minlen[z]=maxlen[y]+1; slink[z]=y; int w=v; while(w!=0&&trans[w][c]==x) { trans[w][c]=y; w=slink[w]; } minlen[y]=maxlen[slink[y]]+1; return z; } void init() { memset(maxlen, 0, sizeof(maxlen)); memset(minlen, 0, sizeof(maxlen)); memset(trans, 0, sizeof(maxlen)); memset(slink, 0, sizeof(maxlen)); n=0; st=new_state(0, -1, NULL, 0); } void addstring(char* s, int len) { int la=st; for(int i=0;i<len;i++) { la=add_char(s[i], la); } this->len=len; } int ji[MAXL+10], id[2*MAXL+10]; void prepare() { memset(ji, 0, sizeof(ji)), memset(id, 0, sizeof(id)); ji[0]=0; for(int i=st;i<=n;i++) ji[maxlen[i]]++; for(int i=1;i<=n;i++) ji[i]+=ji[i-1]; for(int i=st;i<=n;i++) id[ji[maxlen[i]]--]=i; for(int i=n;i>=st;i--) { int now=id[i]; for(int j=0;j<MAXS;j++) { if(trans[now][j]) subamo[now]+=subamo[trans[now][j]]; } } } void deal(int k) { int now=this->st; string s=""; while(k&&now) { for(int i=0;i<MAXS;i++) { if(trans[now][i]) { int to=trans[now][i]; if(subamo[to]>=k) { s.push_back('a'+i); now=to; k--; break; } else { k-=subamo[to]; } } } } printf("%s\n", s.c_str()); } }sam; char s[MAXL]; int main() { scanf("%s", s);int n=strlen(s); sam.init(); sam.addstring(s, n); sam.prepare(); int q;scanf("%d", &q); while(q--) { int k;scanf("%d", &k); sam.deal(k); } //system("pause"); return 0; }
相关文章推荐
- SPOJ SUBLEX Lexicographical Substring Search
- 【spoj SUBLEX】 Lexicographical Substring Search
- SPOJ SUBLEX Lexicographical Substring Search 后缀自动机
- SPOJ 7258 SUBLEX - Lexicographical Substring Search【SAM,我要报警x
- SPOJ SUBLEX Lexicographical Substring Search
- SPOJ SUBLEX - Lexicographical Substring Search
- spoj SUBLEX Lexicographical Substring Search【解法一】
- SPOJ 题目7528 SUBLEX - Lexicographical Substring Search(后缀自动机求排名k的子串)
- SPOJ 7258 SUBLEX - Lexicographical Substring Search (后缀自动机)
- spoj SUBLEX Lexicographical Substring Search【解法二】
- spoj 7258 Lexicographical Substring Search (后缀自动机)
- SPOJ 7258 Lexicographical Substring Search
- ●SPOJ 7258 Lexicographical Substring Search
- [SPOJ7258]SUBLEX - Lexicographical Substring Search(后缀自动机)
- [SP7258 SUBLEX]Lexicographical Substring Search
- spoj 7258 Lexicographical Substring Search (后缀自动机)
- 【SPOJ 7258】Lexicographical Substring Search
- spoj 7258 Lexicographical Substring Search(后缀数组 | 后缀自动机)
- SPOJ Lexicographical Substring Search 后缀自动机
- SPOJ 7258 Lexicographical Substring Search [后缀自动机 DP]