博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 3998 [TJOI2015]弦论
阅读量:6864 次
发布时间:2019-06-26

本文共 3385 字,大约阅读时间需要 11 分钟。

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

Source

思路

后缀自动机,由于后缀自动机对应每一个字串,那么只需要记录每个字串的sizesize,当T=0T=0时为11,当T=1T=1时为他的parentparent树上的子树大小(注意在这种情况下只能计算插入字符中的npnp,而不能将nqnq计算在内)。

代码

#include 
#include
const int maxn=500000;const int maxk=1000000;struct node{ node* tr[26]; node* par; int maxl,size,sum; node() { memset(tr,0,sizeof tr); par=NULL; maxl=size=sum=0; }};struct suffix_automaton{ node samnode[maxk+10]; node* pps[maxk+10]; node* qs; node* qlast; int cnt,tmp[maxk+10]; suffix_automaton() { delete qs; delete qlast; qlast=qs=new node(); cnt=0; } inline int addchr(int ch) { node* p=qlast; node* np=samnode+ ++cnt; np->size=1; np->maxl=qlast->maxl+1; qlast=np; while((p!=NULL)&&(p->tr[ch]==NULL)) { p->tr[ch]=np; p=p->par; } if(p==NULL) { np->par=qs; return 0; } node* q=p->tr[ch]; if(q->maxl!=p->maxl+1) { node* nq=samnode+ ++cnt; nq->size=0; nq->maxl=p->maxl+1; memcpy(nq->tr,q->tr,sizeof q->tr); nq->par=q->par; q->par=np->par=nq; while((p!=NULL)&&(p->tr[ch]==q)) { p->tr[ch]=nq; p=p->par; } } else { np->par=q; } return 0; } inline int sort_maxl() { for(register int i=1; i<=cnt; ++i) { ++tmp[samnode[i].maxl]; } for(register int i=2; i<=cnt; ++i) { tmp[i]+=tmp[i-1]; } for(register int i=cnt; i; --i) { pps[tmp[samnode[i].maxl]--]=samnode+i; } return 0; } inline int calc_size(int t) { if(t) { for(register int i=cnt; i; --i) { if(pps[i]->par!=qs) { pps[i]->par->size+=pps[i]->size; } } } else { for(register int i=1; i<=cnt; ++i) { samnode[i].size=1; } } for(register int i=cnt; i; --i) { pps[i]->sum=pps[i]->size; for(register int j=0; j<26; ++j) { if(pps[i]->tr[j]!=NULL) { pps[i]->sum+=pps[i]->tr[j]->sum; } } } return 0; } inline int dfs(node* p,int k) { if(p->size>=k) { return 0; } k-=p->size; for(register int i=0; i<26; ++i) { if(p->tr[i]!=NULL) { if(p->tr[i]->sum>=k) { putchar(i+'a'); dfs(p->tr[i],k); return 0; } k-=p->tr[i]->sum; } } return 0; } inline int check(int k) { for(register int i=0; i<26; ++i) { if(qs->tr[i]!=NULL) { k-=qs->tr[i]->sum; } } if(k>0) { return 1; } return 0; }};suffix_automaton sam;int n,k,t;char s[maxn+10];int main(){ scanf("%s",s+1); n=strlen(s+1); for(register int i=1; i<=n; ++i) { sam.addchr(s[i]-'a'); } sam.sort_maxl(); scanf("%d%d",&t,&k); sam.calc_size(t); if(sam.check(k)) { puts("-1"); return 0; } sam.dfs(sam.qs,k); return 0;}

转载于:https://www.cnblogs.com/Canopus-wym/p/10376225.html

你可能感兴趣的文章
找不到命令报错bash:command not found解决方案
查看>>
对51CTO的看法
查看>>
userenv和sys_context函数
查看>>
是否会回到起点.回忆只能是回忆
查看>>
原创数据结构算法Flash动画演示课件-Action Script(AS)脚本实现
查看>>
基于Mysql主从同步的读写分离
查看>>
北漂这两年
查看>>
tomcat 日志分割脚本
查看>>
马哥9-4
查看>>
容灾备份技术的分类概述
查看>>
java初学者必看——J2SE小结
查看>>
iOS网络开发(8)文件下载的实现
查看>>
rommon模式下给路由器灌入IOS
查看>>
初识LVS(二)——LVS的DR工作模式
查看>>
vSphere 6.5 新功能 (1) - 全功能 vCenter S
查看>>
1-VMware workstation认识
查看>>
Ubuntu12.04 安装 mongodb
查看>>
【Android】全角字符半角字符工具类
查看>>
Vuebnb:一个用vue.js和Laravel构建的全栈应用
查看>>
什么是shell,shell基础由浅入深,常用的shell命令、用法、技巧
查看>>