LGOJ3975 TJOI2015 弦论

link:TJOI2015 弦论

题目大意:

给定一个字符串,输出在对该字符串所有的非空子串排序后第\(k\)

另外的一个限制是\(T\):子串本质相同但位置不同算\(1\)或多个

\(|s| \leq 5 \times 10^5\)

Solution

“子串排序”,而且数据比较大的时候就要想到后缀自动机了

这个过程有点点像我们在写Treap的时候(就是lyd的书上的代码吧,蒟蒻只学过那一个)

第一步构造一下,套个板子就行

接下来我们先看一下我们的输出代码:

	inline void print(int x,int l)
	{
		if(l<=val[x]) return ;
		l-=val[x];
		for(int i=0;i<26;++i)
		{
			int r=p[x].ch[i]; if(!r) continue;
			if(l>sum[r]){l-=sum[r]; continue;}
			putchar(i+'a'); print(r,l); return ;
		}
	}

\(x\)是当前是哪个节点,\(l\)就是还剩下多少的排位

\(val[]\)就是“本质相同串”,有点点类似我们在\(Treap\)上的每一个节点的\(size\)

\(sum[]\)就是子树大小

\(treap\)\(rank\)太像了(反正我觉得是)

然后我们的工作就转化成了维护\(sum[]\)\(val[]\)

看看这段维护代码,一点一点说吧(如果是有学习需要的访客,请跳过这段代码解释,可能有锅)

		for(int i=1;i<=tot;++i) t[len(i)]++;
		for(int i=1;i<=tot;++i) t[i]+=t[i-1];
		for(int i=1;i<=tot;++i) a[t[len(i)]--]=i;
		//上文都是自动机上的操作
		//下文就是大力统计“和”
		for(int i=tot;i>=1;--i) val[fa(a[i])]+=val[a[i]];
		for(int i=1;i<=tot;++i) cas==0?(sum[i]=val[i]=1):(sum[i]=val[i]);
		val[1]=sum[1]=0;
		for(int i=tot;i>=1;--i)
		{
			for(int j=0;j<26;++j)
			{
				if(p[a[i]].ch[j]) sum[a[i]]+=sum[p[a[i]].ch[j]];
			}
		} 

其实到这里我认为是可理解的(博主理解了)

CODE

#include
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1;char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=2e6+10;
	char s[N];
	struct node{
		int fa,len,ch[26];
		#define fa(x) p[x].fa
		#define len(x) p[x].len
	}p[N];
	int t[N],a[N],sum[N],k,las=1,tot=1,len,cas,val[N];
	inline void addp(int x)
	{
		int tmp=las,np=las=++tot; val[tot]=1; p[np].len=p[tmp].len+1;
		for(;tmp&&!p[tmp].ch[x];tmp=p[tmp].fa) p[tmp].ch[x]=np;
		if(!tmp) p[np].fa=1;
		else 
		{
			int q=p[tmp].ch[x];
			if(p[q].len==p[tmp].len+1) p[np].fa=q;
			else 
			{
				int nq=++tot;
				p[nq]=p[q]; p[nq].len=p[tmp].len+1;
				p[q].fa=p[np].fa=nq;
				for(;tmp&&p[tmp].ch[x]==q;tmp=p[tmp].fa) p[tmp].ch[x]=nq;
			}
		} return ;
	}
	inline void print(int x,int l)
	{
		if(l<=val[x]) return ;
		l-=val[x];
		for(int i=0;i<26;++i)
		{
			int r=p[x].ch[i]; if(!r) continue;
			if(l>sum[r]){l-=sum[r]; continue;}
			putchar(i+'a'); print(r,l); return ;
		}
	}
	signed main()
	{
		scanf("%s",s+1); cas=read(); k=read(); len=strlen(s+1);
		for(int i=1;i<=len;++i) addp(s[i]-'a');
		for(int i=1;i<=tot;++i) t[len(i)]++;
		for(int i=1;i<=tot;++i) t[i]+=t[i-1];
		for(int i=1;i<=tot;++i) a[t[len(i)]--]=i;
		for(int i=tot;i>=1;--i) val[fa(a[i])]+=val[a[i]];
		for(int i=1;i<=tot;++i) cas==0?(sum[i]=val[i]=1):(sum[i]=val[i]);
		val[1]=sum[1]=0;
		for(int i=tot;i>=1;--i)
		{
			for(int j=0;j<26;++j)
			{
				if(p[a[i]].ch[j]) sum[a[i]]+=sum[p[a[i]].ch[j]];
			}
		} 
		if(sum[1]

你可能感兴趣的:(LGOJ3975 TJOI2015 弦论)