P3975 [TJOI2015]弦论
思路
一眼SAM板子,结果敲了一中午。。。
我还是太弱了
题目要求求第k小的子串
我们可以把t=0当成t=1的特殊情况,(所有不同位置的相同子串算作一个就是相当于把所有子串的出现位置个数(endpos大小)全部赋成1)
然后讨论如何递推的求第k小的子串
首先要统计一个sum值,代表从这个状态出发能够到达多少个子串,相当于这个节点后继节点的所有值的和,反向拓扑一下能到那些节点即可
然后逐个dfs每个位置的字符是什么即可
注意
反向拓扑不一定要真的反向建边(狗头),我这么乱搞了。。。
可以把每个点的maxlen从小到大基数排序一发,然后正向拓扑就是从小到大,反向就是从大到小
会快很多
因为乱搞只能开O2过的代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#define int long long
const int MAXN = 500100*2;
using namespace std;
int trans[MAXN][26],suflink[MAXN],endpos[MAXN],maxlen[MAXN],minlen[MAXN],Nodecnt,ispre[MAXN],in[MAXN],sum[MAXN];
char s[MAXN],ans[MAXN];
int new_state(int _maxlen,int _minlen,int *_trans,int _suflink){
++Nodecnt;
maxlen[Nodecnt]=_maxlen;
minlen[Nodecnt]=_minlen;
if(_trans)
for(int i=0;i<26;i++)
trans[Nodecnt][i]=_trans[i];
suflink[Nodecnt]=_suflink;
return Nodecnt;
}
int add_len(int u,int c){
int z=new_state(maxlen[u]+1,0,NULL,0);
ispre[z]=1;
while(u&&trans[u][c]==0){
trans[u][c]=z;
u=suflink[u];
}
if(!u){
suflink[z]=1;
minlen[z]=1;
return z;
}
int v=trans[u][c];
if(maxlen[v]==maxlen[u]+1){
suflink[z]=v;
minlen[z]=maxlen[v]+1;
return z;
}
int y=new_state(maxlen[u]+1,0,trans[v],suflink[v]);
suflink[v]=suflink[z]=y;
minlen[v]=minlen[z]=maxlen[y]+1;
while(u&&trans[u][c]==v){
trans[u][c]=y;
u=suflink[u];
}
minlen[y]=maxlen[suflink[y]]+1;
return z;
}
queue<int> q;
void topu_size(int tx){
for(int i=1;i<=Nodecnt;i++)
in[suflink[i]]++;
for(int i=1;i<=Nodecnt;i++)
if(!in[i])
q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
endpos[x]+=ispre[x];
endpos[suflink[x]]+=endpos[x];
in[suflink[x]]--;
if(!in[suflink[x]])
q.push(suflink[x]);
}
}
int u[MAXN*10],v[MAXN*10],fir[MAXN*10],nxt[MAXN*10],cnt;
void addedge(int ui,int vi){
++cnt;
u[cnt]=ui;
v[cnt]=vi;
nxt[cnt]=fir[ui];
in[vi]++;
fir[ui]=cnt;
}
void topu_sum(int tx){
for(int i=1;i<=Nodecnt;i++){
for(int j=0;j<26;j++)
if(trans[i][j]){
addedge(trans[i][j],i);
}
if(tx==0){
endpos[i]=sum[i]=1;
}
else{
sum[i]=endpos[i];
}
}
sum[1]=endpos[1]=0;
for(int i=1;i<=Nodecnt;i++)
if(!in[i])
q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=fir[x];i;i=nxt[i]){
sum[v[i]]+=sum[x];
in[v[i]]--;
if(!in[v[i]])
q.push(v[i]);
}
}
}
int k,t,n;
int dfs(int pos,int x,int tx){
// printf("pos=%lld x=%lld k=%lld\n",pos,x,k);
if(k<=endpos[x])
return 1;
k-=endpos[x];
for(int i=0;i<26;i++){
if(!trans[x][i])
continue;
// printf("gg %d\n",trans[x][i]);
int mid=sum[trans[x][i]];
if(k>mid)
k-=mid;
else{
// printf("to %d\n",trans[x][i]);
// k-=endpos[trans[x][i]];
ans[pos]='a'+i;
return dfs(pos+1,trans[x][i],tx);
}
}
return -1;
}
signed main(){
freopen("1.in","r",stdin);
scanf("%s",s+1);
scanf("%lld %lld",&t,&k);
n=strlen(s+1);
Nodecnt=1;
int pre=1;
for(int i=1;i<=n;i++)
pre=add_len(pre,s[i]-'a');
// printf("ok\n");
topu_size(t);
topu_sum(t);
// for(int i=1;i<=Nodecnt;i++)
// printf("maxlen=%lld minlen=%lld endpos=%lld suflink=%lld sum=%lld\n",maxlen[i],minlen[i],endpos[i],suflink[i],sum[i]);
int req=dfs(1,1,t);
if(req==-1){
printf("-1\n");
return 0;
}
printf("%s\n",ans+1);
return 0;
}
P3975 [TJOI2015]弦论的更多相关文章
- Luogu P3975 [TJOI2015]弦论
题目链接 \(Click\) \(Here\) 题目大意: 重复子串不算的第\(k\)大子串 重复子串计入的第\(k\)大子串 写法:后缀自动机. 和\(OI\) \(Wiki\)上介绍的写法不太一样 ...
- 洛谷 P3975 [TJOI2015]弦论 解题报告
P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...
- luogu P3975 [TJOI2015]弦论 SAM
luogu P3975 [TJOI2015]弦论 链接 bzoj 思路 建出sam. 子串算多个的,统计preant tree的子树大小,否则就是大小为1 然后再统计sam的节点能走到多少串. 然后就 ...
- [洛谷P3975][TJOI2015]弦论
题目大意:求一个字符串的第$k$大字串,$t$表示长得一样位置不同的字串是否算多个 题解:$SAM$,先求出每个位置可以到达多少个字串($Right$数组),然后在转移图上$DP$,若$t=1$,初始 ...
- 并不对劲的bzoj3998:loj2102:p3975:[TJOI2015]弦论
题目大意 对于一个给定的长度为n(\(n\leq5*10^5\))的字符串, 分别求出不同位置的相同子串算作一个.不同位置的相同子串算作多个时,它的第k(\(k\leq10^9\))小子串是什么 题解 ...
- BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2152 Solved: 716[Submit][Status] ...
- 【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 第二行 ...
随机推荐
- STL之Queue容器
1.Queue容器 1)queue是队列容器,是一种“先进先出”的容器. 2)queue是简单地装饰deque容器而成为另外的一种容器. 3)头文件.#include <queue> 2. ...
- 如何修改Xampp服务器上的mysql密码(图解)
https://www.jb51.net/article/111289.htm https://www.cnblogs.com/Leequik/p/5323795.html 1.点击MySQL的adm ...
- [NOIP2005普及组]采药(01背包)
题目描述 描述 辰辰是个很有潜能.天资聪颖的孩子,他的梦想是称为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到个到处都是草药的山洞里对他说 ...
- Java注解的原理
自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述 ...
- 以太坊erc20转账失败的情况和原因
以太坊erc20转账失败的情况和原因 eth转账失败有多种情况,除了手续费过低以外(Out of gas),众筹额度满了(Bad instruction)也会失败链上转账有可能失败,转账失败转账的币退 ...
- 项目方说性能达到百万TPS,如何测试它的可信度?
项目方说性能达到百万TPS,如何测试它的可信度? 应用系统性能提升的关键在于运维端的接入管理模型(AAA,认证 Authentication.授权 Authorization.计费 Accountin ...
- python 闭包和装饰器
python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...
- 使用 ffmpeg 转换视频格式
ffmpeg 是 *nix 系统下最流行的音视频处理库,功能强大,并且提供了丰富的终端命令,实是日常视频处理的一大利器! 实例 flac 格式转 mp3 音频格式转换非常简单: ffmpeg -i i ...
- GoldenGate 12.3微服务架构与传统架构的区别
随着Oracle GoldenGate 12c(12.3.0.1.0)的发布,引入了可用于复制业务数据的新架构. 多年来,这种架构有着不同的称谓,Oracle终于在最后GA发布的版本中,以“Micro ...
- 本地MySQL的root所创建用户登录发生[Access denied for user 'root1'@'localhost' (using password: YES)]错误的解决方案
1.问题描述: 当在SQLyog中执行以下脚本: CREATE DATABASE IF NOT EXISTS sys; USE sys; CREATE USER root1 IDENTIFIED BY ...