首页 > 代码库 > 【spoj7528】 Lexicographical Substring Search
【spoj7528】 Lexicographical Substring Search
http://www.spoj.com/problems/SUBLEX/ (题目链接)
题意
给出一个字符串,询问其中字典序第K小的子串。
Solution
后缀自动机例题。
构出后缀自动机以后,对每个节点预处理出从这个节点可以到达多少个不同的子串。然后就是类似于在平衡树上查找一样沿着SAM一路查找下去一路更新答案了。
代码借鉴的DaD3Zz大神,感觉好优美。
细节
后缀自动机的节点数是2N的。
代码
// spoj7528#include<algorithm>#include<iostream>#include<cstdlib>#include<cstring>#include<cstdio>#include<cmath>#include<ctime>#define LL long long#define inf 1<<30#define Pi acos(-1.0)#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);using namespace std;const int maxn=1000010;char s[maxn],ans[maxn];int n,K;namespace SAM { int ch[maxn<<1][26],par[maxn<<1],len[maxn<<1],Dargen,last,sz; int b[maxn],id[maxn<<1],sum[maxn<<1]; void Extend(int c) { int np=++sz,p=last;last=np; len[np]=len[p]+1; for (;p && !ch[p][c];p=par[p]) ch[p][c]=np; if (!p) par[np]=Dargen; else { int q=ch[p][c]; if (len[p]+1==len[q]) par[np]=q; else { int nq=++sz;len[nq]=len[p]+1; memcpy(ch[nq],ch[q],sizeof(ch[nq])); par[nq]=par[q]; par[np]=par[q]=nq; for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq; } } } void build() { Dargen=last=sz=1; for (int i=1;i<=n;i++) Extend(s[i]-‘a‘); } void pre() { //貌似这个东西是精髓?一个O(n)的基数排序之后根据parent树的性质对Right集合的大小和一些其它奇奇怪怪的东西进行O(n)的预处理 for (int i=1;i<=sz;i++) b[len[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=1;i<=sz;i++) id[b[len[i]]--]=i; for (int i=sz,S=0;i>=1;i--,S=0) { //sum记录当前节点不同子串个数 for (int j=0;j<26;j++) S+=sum[ch[id[i]][j]]; sum[id[i]]=S+1; } } void query(int K) { int now=Dargen,tot=0; while (K) { for (int i=0;i<26;i++) if (ch[now][i]) { if (sum[ch[now][i]]>=K) { ans[++tot]=‘a‘+i,K--,now=ch[now][i]; break; } else K-=sum[ch[now][i]]; } } ans[++tot]=‘\0‘; }}using namespace SAM;int main() { scanf("%s",s+1); n=strlen(s+1); build(); pre(); int q;scanf("%d",&q); while (q--) { scanf("%d",&K); query(K); puts(ans+1); } return 0;}
【spoj7528】 Lexicographical Substring Search
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。