• 【洛谷P3975】弦论


    题目

    题目链接:https://www.luogu.com.cn/problem/P3975
    为了提高智商,ZJY 开始学习弦论。这一天,她在《String theory》中看到了这样一道问题:对于一个给定的长度为 (n) 的字符串,求出它的第 (k) 小子串是什么。你能帮帮她吗?
    (t)(0) 则表示不同位置的相同子串算作一个,(t)(1) 则表示不同位置的相同子串算作多个。

    思路

    建出 SAM 之后,我们分开讨论 (t=0)(t=1) 的点。
    对于 (t=0) 的点,我们不难发现经过一个点本质不同的子串的数量就是其 SAM 的 DAG 上所能到达的点。因为在这个类之前所有串的后缀都是一致的,而从 DAG 上这个类可以到达的点也就意味着有多少个不同的“前缀”。所以我们直接在 DAG 上记忆化搜索即可。
    对于 (t=1) 的点,经过一个节点的位置不同的子串的数量就是他所代表的类的集合大小。那么我们可以在 parent 树上拓扑求出每一个节点的子树大小,然后再记忆化搜索。
    询问的时候,枚举当前位每一个字符,如果数量不够就减去它的数量,否则输出它继续递归。
    时间复杂度 (O(nk)),其中 (k=26)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010;
    int n,k,t,a[N];
    ll cnt[N];
    char s[N];
    
    struct SAM
    {
    	int tot,last,ch[N][26],fa[N],len[N];
    	ll siz[N];
    	SAM() { tot=last=1; }
    	
    	void ins(int c)
    	{
    		int p=last,np=++tot; 
    		last=np; len[np]=len[p]+1; siz[np]=1;
    		for (;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    		if (!p) fa[np]=1;
    		else
    		{
    			int q=ch[p][c];
    			if (len[q]==len[p]+1) fa[np]=q;
    			else
    			{
    				int nq=++tot;
    				len[nq]=len[p]+1; fa[nq]=fa[q];
    				for (int i=0;i<26;i++) ch[nq][i]=ch[q][i];
    				fa[q]=fa[np]=nq;
    				for (;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    			}
    		}
    	}
    	
    	void topsort()
    	{
    		for (int i=1;i<=tot;i++) cnt[len[i]]++;
    		for (int i=1;i<=tot;i++) cnt[i]+=cnt[i-1];
    		for (int i=1;i<=tot;i++) a[cnt[len[i]]--]=i;
    		for (int i=tot;i>=1;i--) siz[fa[a[i]]]+=siz[a[i]];
    		memset(cnt,0,sizeof(cnt));
    	}
    	
    	void dfs(int x)
    	{
    		if (cnt[x]) return;
    		if (t) cnt[x]=siz[x];
    			else cnt[x]=siz[x]=(x>1);
    		for (int i=0;i<26;i++)
    			if (ch[x][i])
    			{
    				dfs(ch[x][i]);
    				cnt[x]+=cnt[ch[x][i]];
    			}
    	}
    	
    	void query(int x,int k)
    	{
    		if (k<=siz[x]) return;
    		k-=siz[x];
    		for (int i=0;i<26;i++)
    			if (k>cnt[ch[x][i]]) k-=cnt[ch[x][i]];
    			else
    			{
    				putchar(i+'a');
    				query(ch[x][i],k);
    				return;
    			}
    	}
    }sam;
    
    int main()
    {
    	scanf("%s%d%d",s+1,&t,&k);
    	n=strlen(s+1);
    	for (int i=1;i<=n;i++)
    		sam.ins(s[i]-'a');
    	if (t) sam.topsort();
    	cnt[1]=sam.siz[1]=0;
    	sam.dfs(1);
    	if (k>cnt[1]) printf("-1");
    		else sam.query(1,k);
    	return 0;
    }
    
  • 相关阅读:
    设计模式开始--工厂模式
    设计模式开始--UML类之间关系表示
    设计模式开始1--不明觉厉
    Gas Station
    Validate Binary Search Tree
    Word Ladder
    (转)基于快速排序的TOPK算法
    Number of 1 Bits
    Word Search
    Rotate Array
  • 原文地址:https://www.cnblogs.com/stoorz/p/14254034.html
Copyright © 2020-2023  润新知