[BZOJ3998]-[TJOI2015]弦论-后缀自动机

last UPD at 2018.3.14 把之前手滑的地方修正了

说在前面

被这题折磨致死…
第一次写SAM,理解不够,于是被各种细节坑上天=A=
还要复习会考,伤心


题目

BZOJ3998传送门
###题目大意
对于一个给定长度为N的字符串,求它的第K小子串是什么。

输入输出格式

输入格式:
第一行是一个仅由小写英文字母构成的字符串S
第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

输出格式:
输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1


解法

听说这是一道很基础很基础的题
aaaaaaaaaaaaaaaaaaaaaaaaaaaa土拨鼠叫.jpg

维护方法和AC自动机上维护信息差不多…都是通过parent(AC自动机上是fail)和child累加信息
具体做法,在后缀自动机的每个节点上开两个域cnt和sum,cnt表示该节点 代表的字符串集合 出现了多少次,sum表示该节点 代表的字符串集合 所能到达的字符串总个数。
很明显nd->sum = nd->cnt + Σ \Sigma Σnd->child[i]->sum(后缀自动机上的child)

然后关于cnt的计算
如果重复子串只计算一次(T为0),那么所有节点的cnt都应该是1(这里len不会对cnt带来影响,因为len是向前扩展的。换种理解方式,就是说走过不同的前缀,最后到达的节点可能相同,因为它们结束位置相同,它们的sum和cnt也是一样的)
如果重复子串需要累计(T为1),那么在parent树上nd->cnt+= Σ \Sigma Σnd->child[k]->cnt(注意是parent树上,当前串也肯定会在parent树儿子里再出现的,所以要累加上儿子的。这其实就是right集合的大小)

还有还有,因为在建SAM的时候,节点编号的顺序并不是自动机上或者parent树上的顺序,因此只能通过根据length排序来确定拓扑序,不像AC自动机可以直接逆BFS序统计。


下面是自带大常数的代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

long long K ;
int T , lens , bt[1000005] , so[1000005] ;
char ss[500005] ;
struct Node{
	int len ;
	long long cnt , sum ;
	Node *ch[27] , *par ;
}w[1000005] , *root , *last , *tw = w ;

void GG(){
	puts( "-1" ) ;
	exit( 0 ) ;
}

void newNode( Node *&nd ){
	nd = ++tw ;
	nd->len = nd->cnt = nd->sum = 0 ;
	memset( nd->ch , 0 , sizeof( nd->ch ) ) ;
	nd->par = NULL ;
}

void Insert( char cc ){
	Node *now , *tmp = last ;
	newNode( now ) ; now->len = last->len + 1 ;

	int id = cc - 'a' ;
	while( tmp && !tmp->ch[id] ){
		tmp->ch[id] = now ;
		tmp = tmp->par ;
	}
	if( !tmp ) now->par = root ;
	else{
		if( tmp->ch[id]->len == tmp->len + 1 ) {
			now->par = tmp->ch[id] ;
		} else {
			Node *B = tmp->ch[id] , *nB = ++tw ;
			*nB = *B ;
			now->par = B->par = nB ;
			nB->len = tmp->len + 1 ;
			while( tmp && tmp->ch[id] == B ){
				tmp->ch[id] = nB ;
				tmp = tmp->par ;
			}
		}
	}
	last = now ;
}

void build(){
	last = root ;
	for( int i = 0 ; i < lens ; i ++ )
		Insert( ss[i] ) ;
}

void count(){
	for( int i = tw - w ; i ; i -- ){
		Node *nd = w + so[i] ;
		if( !T && nd->cnt ) nd->cnt = 1 ;
		if( nd != root ){
			nd->par->cnt += nd->cnt ;
			nd->sum = nd->cnt ;
		}
		for( int i = 0 ; i < 26 ; i ++ )
			if( nd->ch[i] ) nd->sum += nd->ch[i]->sum ;
	}
}

void solve(){
	newNode( root ) ;
	build() ;
	for( Node *nd = w+1 ; nd <= tw ; nd ++ ) bt[nd->len] ++ ;
	for( int i = 1 ; i <= lens ; i ++ ) bt[i] += bt[i-1] ;
	for( Node *nd = tw ; nd != w ; nd -- ) so[ bt[nd->len]-- ] = nd - w ;

	Node *tmp = root ;
	for( int i = 0 ; i < lens ; i ++ ){
		tmp = tmp->ch[ ss[i] - 'a' ] ;
		tmp->cnt = 1 ;
	}
	count() ;
	if( root->sum < K ) GG() ;
	
	tmp = root ;
	for( int i ; K > 0 ; ){
		for( i = 0 ; i < 26 ; i ++ )
			if( tmp->ch[i] ){
				if( tmp->ch[i]->sum < K ) K -= tmp->ch[i]->sum ;
				else break ;
			}
		printf( "%c" , 'a' + i ) ;
		K -= tmp->ch[i]->cnt ;
		tmp = tmp->ch[i] ;
	}

}

int main(){
	scanf( "%s" , ss ) ;
	lens = strlen( ss ) ;
	scanf( "%d%lld" , &T , &K ) ;
	solve() ;
	return 0 ;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值