LGOJ3975 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<bits/stdc++.h>
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]<k) puts("-1");
else print(1,k),puts("");
return 0;
}
}signed main(){return yspm::main();}
LGOJ3975 TJOI2015 弦论的更多相关文章
- BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2152 Solved: 716[Submit][Status] ...
- Luogu P3975 [TJOI2015]弦论
题目链接 \(Click\) \(Here\) 题目大意: 重复子串不算的第\(k\)大子串 重复子串计入的第\(k\)大子串 写法:后缀自动机. 和\(OI\) \(Wiki\)上介绍的写法不太一样 ...
- 洛谷 P3975 [TJOI2015]弦论 解题报告
P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...
- 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2627 Solved: 881 Description 对于一 ...
- 【BZOJ3998】[TJOI2015]弦论 后缀自动机
[BZOJ3998][TJOI2015]弦论 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T ...
- BZOJ_3998_[TJOI2015]弦论_后缀自动机
BZOJ_3998_[TJOI2015]弦论_后缀自动机 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行 ...
- bzoj3998: [TJOI2015]弦论(SAM+dfs)
3998: [TJOI2015]弦论 题目:传送门 题解: SAM的入门题目(很好的复习了SAM并加强Right集合的使用) 其实对于第K小的字符串直接从root开始一通DFS就好,因为son边是直接 ...
- luogu P3975 [TJOI2015]弦论 SAM
luogu P3975 [TJOI2015]弦论 链接 bzoj 思路 建出sam. 子串算多个的,统计preant tree的子树大小,否则就是大小为1 然后再统计sam的节点能走到多少串. 然后就 ...
- 题解-TJOI2015 弦论
TJOI2015 弦论 字符串 \(s\) 和 \(t\) 和 \(k\).如果 \(t=0\),不同位置的相同子串算 \(1\) 个:如果 \(t=1\),不同位置的相同子串算多个.求 \(k\) ...
随机推荐
- maven打包 invalid entry size Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:1.5.14.RELEASE:repackage (default) on project
打包失败,但是不知是具体是什么引起得,使用mvn -e clean package,定位到报错得代码 在定位到代码,打上断点,使用maven 打包debug模式 找到dubbo.properties, ...
- Ubuntu Teamviewer安装使用
关于Ubuntu环境下teamviewer的安装(亲测可用-) 以下内容均转自:https://blog.csdn.net/weixin_41887832/article/details/798329 ...
- 时间复杂度T(n)
1:概念 T(n)被称为时间复杂度,一般为在某个算法中操作步骤的重复次数与问题规模n的关系,下面一一举例说明 2:具体说明 2.1:常数阶o(1) 无论代码有多少行,只要没有循环等复杂的结构,其算法时 ...
- c# 基础switct---case用于处理多条件的定值的判断
题目:李四的年终工作评定,如果定为A级,则工资涨500元,如果定为B级,则工资涨200元,如果定为C级,工资不变,如果定为D级工资降200元,如果定为E级工资降500元. 设李四原工资为5000,请用 ...
- VMware下的Ubuntu16设置连接主机网络,设置主机下可以通过xshell访问 VMware下的Ubuntu
NAT模式连接 1. 2. 3. 4. 5. 6.
- centos 下使用 pytesseract 识别文字
偶发一个想法搭一个验证码识别工具,网上查了一下有Tesseract 这个工具可以识别,所以有了后面一小时的搭建过程 ps:Ubuntu 下似乎可以直接用包管理工具来安装,我使用的源码编译安装 前提 由 ...
- JAVA--Mybatis-Spring-SpringMVC框架整合
------Mybatis-Spring-SpringMVC框架整合示例----- mybatis SQL映射文件 <?xml version="1.0" encoding= ...
- win32概述
win32基于已有的框架 有意入口函数只有一个 都需要有一个主函数 所有程序的入口都是maincrtstartup tydedef 顾名思义 window是基于c,c++ 又想有自己所特有的数据类型 ...
- python机器学习(1:K_means聚类算法)
一.算法介绍 K-means算法是最简单的也是最著名的划分聚类算法,由于简洁和效率使得他成为所有聚类算法中最广泛使用的.算法的目的是使各个样本与所在均值的误差平方和达到最小(这也是评价K-means算 ...
- upstream(负载均衡)
一.什么是负载均衡 负载均衡,顾名思义是指将负载尽量均衡的分摊到多个不同的服务器,以保证服务的可用性和可靠性,提供给客户更好的用户体验: 负载均衡的直接目标就是尽量发挥多个服务单元的整体效能,要实现这 ...