bzoj 2998 第k小字串
这道题用后缀数组貌似会T。
后缀自动机做法:
t==0:第k小的本质不同字串
首先把后缀自动机建出来,我们会得到一个DAG,并且只存在一个点入度为0(我们称之为根),可以证明字符串的任意一个本质不同的子串(不包括空串)与该自动机上一条起点为根的长度(路径边数)大于0的路径一一对应。所以我们就可以进行DP了,dp[u]表示以u为起点的串的个数,然后有点像在BST中找第k小的思想。
t==1:第k小的普通字串(不同位置但本质相同的要区分)
还是要dp,我yy的一个状态含义是:dp[u]表示,u节点的对应的后缀(right集合中每个位置对应一个后缀)的所有前缀的个数(空串也是前缀,并且不同位置的空串相互区分)。
这样,我们就默认一个长度为n的字符串有(n+1)*(n+2)/2个子串(包括n+1个空串)。
/**************************************************************
Problem: 3998
User: idy002
Language: C++
Result: Accepted
Time:9736 ms
Memory:134596 kb
****************************************************************/ #include <cstdio>
#include <cstring>
#define N 1000010 typedef long long dnt; int n, k, t;
int son[N][], val[N], pnt[N], rsiz[N], ntot, last;
int idgr[N], stk[N], qu[N], bg, ed, top;
dnt dp[N];
char str[N]; void init() {
ntot = ;
pnt[] = -;
}
void append( int c ) {
int p = last;
int np = ++ntot;
val[np] = val[last]+;
while( ~p && !son[p][c] )
son[p][c]=np,p=pnt[p];
if( p==- ) {
pnt[np] = ;
} else {
int q = son[p][c];
if( val[q]==val[p]+ ) {
pnt[np] = q;
} else {
int nq = ++ntot;
memcpy( son[nq], son[q], sizeof(son[nq]) );
val[nq] = val[p]+;
rsiz[nq] = rsiz[q];
pnt[nq] = pnt[q];
pnt[q] = pnt[np] = nq;
while( ~p && son[p][c]==q ) son[p][c]=nq,p=pnt[p];
}
}
last = np;
while( ~np ) {
rsiz[np]++;
np = pnt[np];
}
}
void print() {
for( int u=; u<=ntot; u++ ) {
fprintf( stderr, "%d(dp[%d]=%lld rsiz[%d]=%d): ", u, u, dp[u], u, rsiz[u] );
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
fprintf( stderr, "%c,%d ", c+'a', v );
}
fprintf( stderr, "\n" );
}
}
void make_topo() {
for( int u=; u<=ntot; u++ ) {
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
idgr[v]++;
}
}
top = ;
for( int u=; u<=ntot; u++ )
if( idgr[u]== )
stk[++top] = u;
bg = , ed = ;
while( top ) {
int u=stk[top--];
qu[++ed] = u;
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
idgr[v]--;
if( idgr[v]== )
stk[++top] = v;
}
}
}
void dodp( int s ) {
make_topo();
rsiz[s] = ;
if( t== )
for( int i=; i<=ed; i++ )
rsiz[qu[i]] = ;
for( int i=ed; i>=; i-- ) {
int u=qu[i];
dp[u] = rsiz[u];
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
dp[u] += dp[v];
}
}
if( dp[]<k ) {
printf( "-1\n" );
return;
}
int u = ;
int kth = k;
while() {
if( kth<=rsiz[u] ) {
printf( "\n" );
return;
} else kth-=rsiz[u];
for( int c=; c<; c++ ) {
int v=son[u][c];
if( !v ) continue;
if( dp[v]>=kth ) {
u = v;
printf( "%c", c+'a' );
break;
} else {
kth -= dp[v];
}
}
}
}
int main() {
scanf( "%s", str );
scanf( "%d%d", &t, &k );
init();
for( int i=; str[i]; i++ )
append( str[i]-'a' );
dodp();
// print();
}
bzoj 2998 第k小字串的更多相关文章
- [bzoj P4504] K个串
[bzoj P4504] K个串 [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次 ...
- bzoj : 4504: K个串 区间修改主席树
4504: K个串 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 268 Solved: 110[Submit][Status][Discuss] ...
- bzoj 4504: K个串 可持久化线段树+堆
题目: Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一 个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计一次). 兔子们想 ...
- bzoj4504 k个串 kstring 可持久化线段树 (标记永久化)
[fjwc2015]k个串 kstring [题目描述] 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只 ...
- 数据结构(主席树):COGS 2213. K个串
2213. K个串 ★★★★ 输入文件:bzoj_4504.in 输出文件:bzoj_4504.out 简单对比时间限制:20 s 内存限制:512 MB [题目描述] 兔子们在玩k个 ...
- 问题 K: 周期串plus
问题 K: 周期串plus 时间限制: 1 Sec 内存限制: 128 MB提交: 682 解决: 237[提交] [状态] [命题人:外部导入] 题目描述 如果一个字符串可以由某个长度为k的字符 ...
- hiho#1449 重复旋律6 求长度为k的串最大次数 后缀自动机
题目传送门 题目大意:求长度为k的串的最大次数,把k从1到length的所有答案全部输出. 思路: 这道题放在$SAM$里就是求长度$k$对应的所有$right$集中最大的大小. 我们以$aabab$ ...
- 【BZOJ4504】K个串 可持久化线段树+堆
[BZOJ4504]K个串 Description 兔子们在玩k个串的游戏.首先,它们拿出了一个长度为n的数字序列,选出其中的一个连续子串,然后统计其子串中所有数字之和(注意这里重复出现的数字只被统计 ...
- BZOJ 4504: K个串
题目大意: 求一个序列的第k大的子串和. 题解: 对于一个右端点找最优的左端点,扔进堆里. 每次取堆顶,将这个右端点可以选择的左端点的区间分成两段,扔进堆里,重复k次. 现在需要对于一个固定的右端点, ...
随机推荐
- CSS ... 文本溢出用省略号代替
{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap } text-overflow 属性规定当文本溢出包含元素时发生的事情. c ...
- imperva-指定url禁止访问
指定url禁止访问 应用到那个网站 访问一下查看告警
- rabbitmq之后台管理和用户设置(三)
前言 前面介绍了erlang环境的安装和rabbitmq环境安装,接下来介绍rabbitmq的web管理和用户设置. 启用后台管理插件 通过后台管理插件我们可以动态监控mq的流量,创建用户,队列等. ...
- Shell-help格式详解
前言 linux shell命令通常可以通过-h或--help来打印帮助说明,或者通过man命令来查看帮助,有时候我们也会给自己的程序写简单的帮助说明,其实帮助说明格式是有规律可循的 帮助示例 下面是 ...
- OpenJ_POJ 1058 Guideposts
Problem OpenJ_POJ Solution 如果我们用 \(G\) 来表示邻接矩阵,那么答案其实就是求\(\sum_{k|i}^n \binom n i G^i\) 为了消除整除的限制,我们 ...
- git忽略特殊文件或文件夹
1.在项目目录中添加“.gitignore”文件,项目目录就是你存放git工程的目录就是有“.git”目录的目录 vi .gitignore 2.在文件中添加如下内容,其中“/runtime/”是忽略 ...
- MyBatis3-实现MyBatis分页
此文章中的例子是沿用上一篇文章http://www.cnblogs.com/EasonJim/p/7055499.html的Spring MVC集成的例子改装的. MyBatis分页有以下方式实现: ...
- 查找Mysql慢查询Sql语句
一.MySQL数据库有几个配置选项可以帮助我们及时捕获低效SQL语句 1,slow_query_log 这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句. 2,long_query_tim ...
- SQL 标量函数-----日期函数 day() 、month()、year()
select day(createtime) from life_unite_product --取时间字段的天值 select month(createtime) from life_unite_p ...
- 教您如何进行SQL跨表更新
SQL跨表更新数据是在使用SQL数据库中比较常用的,下面就将为您详细介绍SQL跨表更新数据的步骤,希望对您学习SQL跨表更新数据有所启迪. 原始数据如下,首先是表结构 A_dept的初始数据 A_em ...