zoukankan      html  css  js  c++  java
  • 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;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    解决Could not load file or assembly CefSharp.Core.dll的问题
    操作AppConfig.xml中AppSettings对应值字符串
    SqlServer根据时段统计数据
    Jquery Validation 多按钮,多表单,分组验证
    HDU 4630 No Pain No Game 线段树 和 hdu3333有共同点
    二叉查找树模板
    五边形数定理
    HDU 4651 Partition 整数划分,可重复情况
    CSU 1114 平方根大搜索 java大数
    hdu 4869 Turn the pokers
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13341931.html
Copyright © 2011-2022 走看看