【刷题】BZOJ 3998 [TJOI2015]弦论
Description
对于一个给定长度为N的字符串,求它的第K小子串是什么。
Input
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。
Output
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1
Sample Input
aabc
0 3
Sample Output
aab
HINT
N<=5*10^5
T<2
K<=10^9
Solution
建SAM
首先对于不能重复的,那么SAM里每个节点的 \(size\) ,即出现次数,直接赋为 \(1\) 即可,然后类似与平衡树找第 \(k\) 大在SAM里面dfs就好了
对于可重复的,那么一个节点的出现次数就是parent树中的子树的和,其余跟上面一模一样
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=500000+10;
int n,len[MAXN<<1],fa[MAXN<<1],ch[MAXN<<1][30],cnt[MAXN],rk[MAXN<<1],las=1,tot=1,size[MAXN<<1],sum[MAXN<<1],opt,k;
char s[MAXN];
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void extend(int c)
{
	int p=las,np=++tot;
	las=np;
	len[np]=len[p]+1;size[np]=1;
	while(p&&!ch[p][c])ch[p][c]=np,p=fa[p];
	if(!p)fa[np]=1;
	else
	{
		int q=ch[p][c];
		if(len[q]==len[p]+1)fa[np]=q;
		else
		{
			int nq=++tot;
			fa[nq]=fa[q];
			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
			len[nq]=len[p]+1,fa[q]=fa[np]=nq;
			while(p&&ch[p][c]==q)ch[p][c]=nq,p=fa[p];
		}
	}
}
inline void dfs(int x,int k)
{
	k-=size[x];
	if(k<=0)return ;
	for(register int i=1;i<=26;++i)
		if(ch[x][i])
		{
			if(sum[ch[x][i]]>=k)
			{
				putchar(i+'a'-1);
				dfs(ch[x][i],k);
				return ;
			}
			else k-=sum[ch[x][i]];
		}
}
int main()
{
	scanf("%s",s+1);
	read(opt);read(k);
	n=strlen(s+1);
	for(register int i=1;i<=n;++i)extend(s[i]-'a'+1);
	for(register int i=1;i<=tot;++i)cnt[len[i]]++;
	for(register int i=1;i<=n;++i)cnt[i]+=cnt[i-1];
	for(register int i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
	if(opt)
		for(register int i=tot;i>=1;--i)size[fa[rk[i]]]+=size[rk[i]];
	else
		for(register int i=1;i<=tot;++i)size[i]=1;
	size[1]=0;
	for(register int i=tot;i>=1;--i)
	{
		sum[rk[i]]=size[rk[i]];
		for(register int j=1;j<=26;++j)sum[rk[i]]+=sum[ch[rk[i]][j]];
	}
	if(k>sum[1])puts("-1");
	else dfs(1,k);
	return 0;
}
												
											【刷题】BZOJ 3998 [TJOI2015]弦论的更多相关文章
- BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]
		
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2152 Solved: 716[Submit][Status] ...
 - ●BZOJ 3998 [TJOI2015]弦论
		
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3998题解: 后缀自动机. 当T=0时, 由于在后缀自动机上沿着trans转移,每个串都是互不 ...
 - BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
		
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
 - bzoj 3998: [TJOI2015]弦论
		
Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...
 - bzoj 3998 [TJOI2015]弦论——后缀自动机
		
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 相同子串算多个的话,先求好 right ,然后求一个 sm 表示走到这个点之后有几种走 ...
 - BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp
		
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...
 - bzoj 3998: [TJOI2015]弦论【SA+二分||SAM】
		
SA的话t==0直接预处理出每个后缀的不同串贡献二分即可,然后t==1就按字典序枚举后缀,然后跳右端点计算和当前后缀的前缀相同的子串个数,直到第k个 不过bzoj上会T #include<ios ...
 - BZOJ.3998.[TJOI2015]弦论(后缀自动机)
		
题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...
 - BZOJ 3998 [TJOI2015]弦论 ——后缀自动机
		
直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...
 
随机推荐
- [python]PyCharm安装与激活
			
一.安装 1.去官网下载安装包(http://www.jetbrains.com/pycharm/download/#section=windows) 2.下载完成之后双击即可点击安装,按照自己需求选 ...
 - LeetCode:36. Valid Sudoku(Medium)
			
1. 原题链接 https://leetcode.com/problems/valid-sudoku/description/ 2. 题目要求 给定一个 9✖️9 的数独,判断该数独是否合法 数独用字 ...
 - DE1-SOC工程helloworld-第一篇(未完成)
			
1. 参考官方的文档,第一个问题就是电脑上需要安装ubuntu虚拟机吗? 2. 创建一个“Hello world”工程:在Linux terminal 上打印信息. 3. 说是让安装个EDS软件,先去 ...
 - Java子类与父类之间的类型转换
			
1.向上转换 父类的引用变量指向子类变量时,子类对象向父类对象向上转换.从子类向父类的转换不需要什么限制,只需直接蒋子类实例赋值给父类变量即可,这也是Java中多态的实现机制. 2.向下转换 在父类变 ...
 - explain获得使用的key的数据
			
bool Explain_join::explain_key_and_len() { if (tab->ref.key_parts) return explain_key_and_len_ind ...
 - centos下php环境安装redis
			
一.安装redis(仅可在服务器使用,尚不能通过浏览器访问) (1)首先下载redis:wget http://download.redis.io/releases/redis-4.0.9.tar.g ...
 - angular-列表进行添加、编辑等操作时此行变色。
			
今天接触了一个功能,就是在一个列表中,当你新增或者对第N列进行编辑,删除等操作时这一列会变颜色.让用户对操作了哪行数据更认识更清晰,刷新之后这行的颜色就会消失.我觉得这个很有意思,记录一下.效果如下. ...
 - HDU - 6441(费马大定理)
			
链接:HDU - 6441 题意:已知 n,a,求 b,c 使 a^n + b^n = c^n 成立. 题解:费马大定理 1.a^n + b^n = c^n,当 n > 2 时无解: 2. 当 ...
 - Python全栈 Web(HTML基础语法)
			
原文地址: https://yq.aliyun.com/articles/632672 .............................................. ...
 - POJ 2069 Super Star(计算几何の最小球包含+模拟退火)
			
Description During a voyage of the starship Hakodate-maru (see Problem 1406), researchers found stra ...