●SPOJ 7258 Lexicographical Substring Search

Posted *ZJ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了●SPOJ 7258 Lexicographical Substring Search相关的知识,希望对你有一定的参考价值。

题链:

http://www.spoj.com/problems/SUBLEX/
题解:

后缀自动机。
首先,因为相同的子串都被存在了自动机的同一个状态里面,所以这就很自然的避免了重复子串的问题。
然后考虑自动机里面的转移trans,发现其构成了一个DAG,且从一个状态出发,DFS下去就可以得到所有的不重复的串;
所以我们按照拓扑序对状态排序,然后DP计算出从每个状态出发可以到达多少个子串。
转移方程:$dp[p]=\sum_{trans(p,*)=q,q!=0}dp[q]+1$
然后对于每个输入的k,在自动机里面配合dp数组去dfs就好。

代码:

 

#include<bits/stdc++.h>
#define MAXN 90005
#define ll long long
using namespace std;
ll cnt[MAXN*3];
struct SAM{
	int size,last;
	int maxs[MAXN*3],trans[MAXN*3][26],parent[MAXN*3];
	int Newnode(int a,int b){
		++size; maxs[size]=a;
		memcpy(trans[size],trans[b],sizeof(trans[b]));
		return size;
	}
	void Extend(int x){
		static int p,np,q,nq;
		p=last; last=np=Newnode(maxs[p]+1,0);
		for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
		if(!p) parent[np]=1;
		else{
			q=trans[p][x];
			if(maxs[p]+1!=maxs[q]){
				nq=Newnode(maxs[p]+1,q);
				parent[nq]=parent[q];
				parent[q]=parent[np]=nq;
				for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
			}
			else parent[np]=q;
		}
	}
	void Build(char *S){
		memset(trans[0],0,sizeof(trans[0]));
		size=0; last=Newnode(0,0);
		for(int i=0;S[i];i++) Extend(S[i]-‘a‘);
	}
}SUF;
void DP(){
	static int in[MAXN*3],A[MAXN*3],ant,q;
	queue<int>Q;
	for(int p=1;p<=SUF.size;p++)
		for(int c=0;c<26;c++){
			q=SUF.trans[p][c]; if(!q) continue;
			in[q]++;
		}
	Q.push(1);
	while(!Q.empty()){
		int p=Q.front(); Q.pop(); A[++ant]=p;
		for(int c=0;c<26;c++){
			q=SUF.trans[p][c]; if(!q) continue;
			in[q]--; if(!in[q]) Q.push(q);
		}
	}
	for(int i=ant,p;i;i--){
		p=A[i]; cnt[p]=(p==1?0:1);
		for(int c=0;c<26;c++){
			q=SUF.trans[p][c]; if(!q) continue;
			cnt[p]+=cnt[q];
		}
	}
//	printf("%lld\n",cnt[1]);
}
void dfs(int p,int k,char from){
	static int i,q;
	static char ans[MAXN];
	if(p==1) i=0; else k--,ans[i++]=from;
	if(!k) return (void)(ans[i]=0,puts(ans));
	for(int c=0;c<26;c++){
		q=SUF.trans[p][c]; if(!q) continue;
		if(k<=cnt[q]){dfs(q,k,‘a‘+c); break;}
		k-=cnt[q];
	}
}
int main(){
	static char S[MAXN];
	scanf("%s",S);
	SUF.Build(S);
	DP();
	int Q,K; scanf("%d",&Q);
	while(Q--){
		scanf("%d",&K);
		dfs(1,K,0);
	}
	return 0;
}

 

  

 

以上是关于●SPOJ 7258 Lexicographical Substring Search的主要内容,如果未能解决你的问题,请参考以下文章

●SPOJ 7258 Lexicographical Substring Search

spoj 7258 SUBLEX(求第k大字串

SPOJ 7258 Lexicographical Substring Search(后缀自动机)

为啥我的 SPOJ GCD2 代码在 SPOJ 上出错?

SPOJ 问题 - 这里出了啥问题?

SPOJ AEROLITE