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

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

思路

一眼SAM板子,结果敲了一中午。。。

我还是太弱了
题目要求求第k小的子串
我们可以把t=0当成t=1的特殊情况,(所有不同位置的相同子串算作一个就是相当于把所有子串的出现位置个数(endpos大小)全部赋成1)
然后讨论如何递推的求第k小的子串
首先要统计一个sum值,代表从这个状态出发能够到达多少个子串,相当于这个节点后继节点的所有值的和,反向拓扑一下能到那些节点即可
然后逐个dfs每个位置的字符是什么即可

注意

反向拓扑不一定要真的反向建边(狗头),我这么乱搞了。。。

可以把每个点的maxlen从小到大基数排序一发,然后正向拓扑就是从小到大,反向就是从大到小
会快很多

因为乱搞只能开O2过的代码

#include 
#include
#include
#include
#include
#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
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;}

转载于:https://www.cnblogs.com/dreagonm/p/10516460.html

你可能感兴趣的文章
[翻译]CURAND Libaray--Host API--(2)
查看>>
Delphi xe5 编译报environment.proj错误的解决
查看>>
PHP变量作用域
查看>>
力挺8天入门wpf【转载】
查看>>
Linux模块
查看>>
kendo grid输入框验证方法
查看>>
[转]一致性哈希算法及其在分布式系统中的应用
查看>>
CAS与LDAP集成
查看>>
JQuery巧妙利用CSS操作打印样式
查看>>
(转载)JWebUnit做Web项目自动化测试
查看>>
牛气冲天的Iframe应用笔记
查看>>
LINQ基础概述
查看>>
emacs之配置etags-select
查看>>
搜索引擎(lucene及周边) 涉及的一些算法总结
查看>>
elasticsearch 口水篇(3)java客户端 - Jest
查看>>
在Linux下怎么确定哪个网卡对应哪个接口?
查看>>
VS2008 SP1 安装卡在 VS90sp1-KB945140-X86-CHS的解决方法
查看>>
与众不同 windows phone (17) - Graphic and Animation(画图和动画)
查看>>
wamp修改端口
查看>>
性能超越 Redis 的 NoSQL 数据库 SSDB
查看>>