SPOJ 7258 SUBLEX (SAM)
生活随笔
收集整理的這篇文章主要介紹了
SPOJ 7258 SUBLEX (SAM)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
轉(zhuǎn)載請注明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents??? by---cxlove ??
題目:給出一個串,查詢字典序排在第k個的是哪個子串
http://www.spoj.pl/problems/SUBLEX/?
由于SAM能遍歷所有的子串,只要預(yù)處理出某個結(jié)點的后繼中有多少個不同的子串就可以了。
首先以每個結(jié)點為終態(tài)算一個子串,所以初始化計數(shù)為1。
然后按照拓?fù)湫?#xff0c;用后繼更新pre。類似數(shù)DP那種。
SPOJ很卡時,需要各種優(yōu)化,首先是經(jīng)典的拓?fù)洹?/span>
一次預(yù)處理,把后繼全部存好,以為相應(yīng)的字母。
有個地方需要注意,在查詢的時候,有個k--。因為以當(dāng)前字母結(jié)束也是一個子串,所以需要減掉
#include<iostream> #include<cstdio> #include<map> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #include<set> #include<string> #include<queue> #define inf 100000005 #define M 40 #define N 200015 #define maxn 300005 #define eps 1e-10 #define zero(a) fabs(a)<eps #define Min(a,b) ((a)<(b)?(a):(b)) #define Max(a,b) ((a)>(b)?(a):(b)) #define pb(a) push_back(a) #define mp(a,b) make_pair(a,b) #define mem(a,b) memset(a,b,sizeof(a)) #define LL unsigned long long #define MOD 1000000007 #define lson step<<1 #define rson step<<1|1 #define sqr(a) ((double)(a)*(a)) #define Key_value ch[ch[root][1]][0] #define test puts("OK"); #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; struct SAM {SAM *pre,*son[26];int len,cnt; }*root,*tail,que[N],*b[N]; char str[N/2]; int son[N][26],cnt[N]; int tot=0; int c[N]; char ch[N][26]; void add(int c,int l) {SAM *p=tail,*np=&que[tot++];np->len=l;while(p&&p->son[c]==NULL) p->son[c]=np,p=p->pre;if(p==NULL) np->pre=root;else{SAM *q=p->son[c];if(p->len+1==q->len) np->pre=q;else{SAM *nq=&que[tot++];*nq=*q;nq->len=p->len+1;np->pre=q->pre=nq;while(p&&p->son[c]==q) p->son[c]=nq,p=p->pre;}}tail=np; } void slove(int k) {int l=0;int now=0;while(k){for(int i=0;i<cnt[now];i++){if(k>que[son[now][i]].cnt){k-=que[son[now][i]].cnt;}else{str[l++]=ch[now][i];now=son[now][i];k--;break;}}}str[l]='\0';puts(str); } int main() {root=tail=&que[tot++];scanf("%s",str);int l=strlen(str);for(int i=0;str[i];i++) add(str[i]-'a',i+1);for(int i=0;i<tot;i++) c[que[i].len]++;for(int i=1;i<tot;i++) c[i]+=c[i-1];for(int i=0;i<tot;i++) b[--c[que[i].len]]=&que[i];for(int i=0;i<tot;i++) que[i].cnt=1;for(int i=tot-1;i>=0;i--){SAM *p=b[i];for(int j=0;j<26;j++){if(p->son[j]){int u=p-que,v=p->son[j]-que;son[u][cnt[u]]=v;ch[u][cnt[u]++]=j+'a';p->cnt+=p->son[j]->cnt;}}}int q,k;scanf("%d",&q);while(q--){scanf("%d",&k);slove(k);}return 0; }
總結(jié)
以上是生活随笔為你收集整理的SPOJ 7258 SUBLEX (SAM)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对静态页面的一些理解
- 下一篇: PHP博客程序全集