SPOJ7258--SUBLEX(SAM)

来源:互联网 发布:发乎于情止乎于礼 编辑:程序博客网 时间:2024/06/01 22:30
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove  

题目:给出一个串,查询字典序排在第k个的是哪个子串

http://www.spoj.pl/problems/SUBLEX/

由于SAM能遍历所有的子串,只要预处理出某个结点的后继中有多少个不同的子串就可以了。

首先以每个结点为终态算一个子串,所以初始化计数为1。

然后按照拓扑序,用后继更新pre。类似数DP那种。

SPOJ很卡时,需要各种优化,首先是经典的拓扑。

一次预处理,把后继全部存好,以为相应的字母。

有个地方需要注意,在查询的时候,有个k--。因为以当前字母结束也是一个子串,所以需要减掉

 

#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;}

 

自己的代码:

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define maxn 90080#define LL long long intchar str[maxn],ans[maxn];int pos = 0;struct SAM{    SAM *pre,*son[26];    int len,sonnum,Son[26];char ch[26];LL g;}que[maxn<<1],*root,*tail,*b[maxn<<1];int tot;int C[maxn<<1];void add(int c,int l){    SAM *p=tail,*np=&que[tot++];    np->len=l;tail=np;    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;        }    }}void init(int n){tot = 0;pos = 0;/*for(int i = 0;i < n;i++){que[i].g = 0;que[i].pre = NULL;que[i].sonnum = 0;for(int j = 0;j < 26;j++){que[i].son[j] = NULL;}memset(que[i].son,0,sizeof(que[i].son));}*/root = tail = &que[tot++];//memset(C,0,sizeof(C));}inline int max(int a,int b){return a>b?a:b;}void dfs(SAM * now,int k){if(k == 0)return;for(int i = 0;i < now -> sonnum;i++){if(now -> son[now -> Son[i]] -> g >= k){ans[pos++] = now -> ch[i];dfs(now -> son[now ->Son[i]],k-1);return;}else k -= now -> son[now -> Son[i]] -> g;}}int main(){//freopen("in.txt","r",stdin);scanf("%s",str);int len = strlen(str);////init(len << 1);/////////////for(int i = 0;i < len;i++){add(str[i] - 'a',i + 1);}//////////for(int i = 0;i < tot;i++)C[que[i].len]++;///////for(int i = 1;i <= len;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].g = 1;///////////for(int i = tot-1;i >= 0;i--){for(int j = 0;j < 26;j++){if(b[i]->son[j]){b[i] -> Son[b[i]->sonnum] = j;b[i] -> ch[b[i]->sonnum] = j+'a';b[i] -> sonnum++;b[i] -> g += b[i] -> son[j] -> g;}}}/////////int q;scanf("%d",&q);while(q--){int k;scanf("%d",&k);pos = 0;dfs(&que[0],k);ans[pos++] = '\0';printf("%s\n",ans);}return 0;}


 


#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define maxn 90080#define LL long long intchar str[maxn],ans[maxn];int pos = 0;struct SAM{    SAM *pre,*son[26];    int len,sonnum,Son[26];char ch[26];LL g;}que[maxn<<1],*root,*tail,*b[maxn<<1];int tot;int C[maxn<<1];void add(int c,int l){    SAM *p=tail,*np=&que[tot++];    np->len=l;tail=np;    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;        }    }}void init(int n){tot = 0;pos = 0;/*for(int i = 0;i < n;i++){que[i].g = 0;que[i].pre = NULL;que[i].sonnum = 0;for(int j = 0;j < 26;j++){que[i].son[j] = NULL;}memset(que[i].son,0,sizeof(que[i].son));}*/root = tail = &que[tot++];//memset(C,0,sizeof(C));}inline int max(int a,int b){return a>b?a:b;}void dfs(SAM * now,int k){if(k == 0)return;for(int i = 0;i < now -> sonnum;i++){if(now -> son[now -> Son[i]] -> g >= k){ans[pos++] = now -> ch[i];dfs(now -> son[now ->Son[i]],k-1);return;}else k -= now -> son[now -> Son[i]] -> g;}}int main(){//freopen("in.txt","r",stdin);scanf("%s",str);int len = strlen(str);////init(len << 1);/////////////for(int i = 0;i < len;i++){add(str[i] - 'a',i + 1);}//////////for(int i = 0;i < tot;i++)C[que[i].len]++;///////for(int i = 1;i <= len;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].g = 1;///////////for(int i = tot-1;i >= 0;i--){for(int j = 0;j < 26;j++){if(b[i]->son[j]){b[i] -> Son[b[i]->sonnum] = j;b[i] -> ch[b[i]->sonnum] = j+'a';b[i] -> sonnum++;b[i] -> g += b[i] -> son[j] -> g;}}}/////////int q;scanf("%d",&q);while(q--){int k;scanf("%d",&k);pos = 0;dfs(&que[0],k);ans[pos++] = '\0';printf("%s\n",ans);}return 0;}