luogu P3975 [TJOI2015]弦论

\(t=0\) 时:考虑 \(dp[i]\) 表示到了后缀自动机上的点 \(i\),往后走还能形成多少子串。转移很显然:\(dp[i]=1+\sum dp[nxt_i]\)。加一是因为可以直接停下,\(nxt_i\) 代表 \(i\)\(nxt_i\) 有一条边。然后想主席树之类的查询就可以了。

\(t=1\) 时:转移方程变化一下:\(dp[i]=appear[i]+\sum dp[nxt_i]\)\(appear[i]\) 表示状态 \(i\) 在原串中出现的次数。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=2000000;
int n,fuck[N],cnm;
char s[N];

struct Suffix_DFA
{
	int last,Siz,head[N],ans[N],cnt,ans1[N];
	struct SAM
	{
		int link,ch[30],len,end;
	}sam[N];
	struct Edge
	{
		int nxt,to;
	}g[N*2];
	
	void add(int from,int to)
	{
		g[++cnt].nxt=head[from];
		g[cnt].to=to;
		head[from]=cnt;
	}
	
	void SAM_Extend(int k)
	{
		int cur=++Siz;
		sam[cur].len=sam[last].len+1,sam[cur].end=1;
		int p=last;
		while(p!=-1&&!sam[p].ch[k])
			sam[p].ch[k]=cur,
			p=sam[p].link;
		if(p==-1)
			sam[cur].link=0;
		else
		{
			int q=sam[p].ch[k];
			if(sam[q].len==sam[p].len+1)
				sam[cur].link=q;
			else
			{
				int clone=++Siz;
				sam[clone].len=sam[p].len+1;
				sam[clone].link=sam[q].link;
				for (int i=0;i<26;i++)
					sam[clone].ch[i]=sam[q].ch[i];
				while(p!=-1&&sam[p].ch[k]==q)
					sam[p].ch[k]=clone,
					p=sam[p].link;
				sam[q].link=sam[cur].link=clone;
			}
		}
		last=cur;
	}
	
	void dfs(int x)
	{
		for (int i=head[x];i;i=g[i].nxt)
			dfs(g[i].to),
			sam[x].end+=sam[g[i].to].end;
	}
	
	void DP(int x)
	{
		ans[x]=1,ans1[x]=sam[x].end;
		for (int i=0;i<26;i++)
		{
			int v=sam[x].ch[i];
			if(v==0) continue;
			if(ans[v]!=-1) ans[x]+=ans[v],ans1[x]+=ans1[v];
			else DP(v),ans[x]+=ans[v],ans1[x]+=ans1[v];
		}
	}
	
	int work()
	{
		sam[0].link=-1;
		for (int i=1;i<=n;i++)
			SAM_Extend(s[i]-'a');
		for (int i=1;i<=Siz;i++)
			add(sam[i].link,i);
		dfs(0);
		memset(ans,-1,sizeof(ans));
		DP(0);
	}
	
	int calc(int x)
	{
		return ans[x];
	}
	
	int calc1(int x)
	{
		return ans1[x];
	}
	
	void Query(int k,int x,int t)
	{
		int now=t?sam[x].end:1;
		if(x==0) now=0;
		if(k<=now) return;
		for (int i=0;i<26;i++)
		{
			int v=sam[x].ch[i];
			if(v==0) continue;
			if(t==0)
			{
				if(k-now>calc(sam[x].ch[i]))
					now+=calc(sam[x].ch[i]);
				else
				{
					fuck[++cnm]=i;
					Query(k-now,sam[x].ch[i],t);
					break; 
				}
			}
			else
			{
				if(k-now>calc1(sam[x].ch[i]))
					now+=calc1(sam[x].ch[i]);
				else
				{
					fuck[++cnm]=i;
					Query(k-now,sam[x].ch[i],t);
					break; 
				}
			}
		}
	}
}S;

void init()
{
	scanf("%s",s+1);
	n=strlen(s+1);
}

void work()
{
	S.work();
	int t,x;
	scanf("%d %d",&t,&x);
	S.ans1[0]-=S.sam[0].end,S.ans[0]--;
	if((t?S.ans1[0]:S.ans[0])<x)
	{
		puts("-1");
		return;
	}
	S.ans[0]=S.ans1[0]=S.sam[0].end=0;
	S.Query(x,0,t);
	for (int i=1;i<=cnm;i++)
		printf("%c",fuck[i]+'a');
}

int main()
{
	init();
	work();
	return 0;
}
posted @ 2020-07-19 23:08  With_penguin  阅读(102)  评论(0编辑  收藏  举报