思路

一眼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]弦论的更多相关文章

  1. Luogu P3975 [TJOI2015]弦论

    题目链接 \(Click\) \(Here\) 题目大意: 重复子串不算的第\(k\)大子串 重复子串计入的第\(k\)大子串 写法:后缀自动机. 和\(OI\) \(Wiki\)上介绍的写法不太一样 ...

  2. 洛谷 P3975 [TJOI2015]弦论 解题报告

    P3975 [TJOI2015]弦论 题目描述 为了提高智商,ZJY开始学习弦论.这一天,她在<String theory>中看到了这样一道问题:对于一个给定的长度为\(n\)的字符串,求 ...

  3. luogu P3975 [TJOI2015]弦论 SAM

    luogu P3975 [TJOI2015]弦论 链接 bzoj 思路 建出sam. 子串算多个的,统计preant tree的子树大小,否则就是大小为1 然后再统计sam的节点能走到多少串. 然后就 ...

  4. [洛谷P3975][TJOI2015]弦论

    题目大意:求一个字符串的第$k$大字串,$t$表示长得一样位置不同的字串是否算多个 题解:$SAM$,先求出每个位置可以到达多少个字串($Right$数组),然后在转移图上$DP$,若$t=1$,初始 ...

  5. 并不对劲的bzoj3998:loj2102:p3975:[TJOI2015]弦论

    题目大意 对于一个给定的长度为n(\(n\leq5*10^5\))的字符串, 分别求出不同位置的相同子串算作一个.不同位置的相同子串算作多个时,它的第k(\(k\leq10^9\))小子串是什么 题解 ...

  6. BZOJ 3998: [TJOI2015]弦论 [后缀自动机 DP]

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2152  Solved: 716[Submit][Status] ...

  7. 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )

    3998: [TJOI2015]弦论 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2627  Solved: 881 Description 对于一 ...

  8. 【BZOJ3998】[TJOI2015]弦论 后缀自动机

    [BZOJ3998][TJOI2015]弦论 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T ...

  9. BZOJ_3998_[TJOI2015]弦论_后缀自动机

    BZOJ_3998_[TJOI2015]弦论_后缀自动机 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行 ...

随机推荐

  1. html5-table布局

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  2. Sitecore CMS中更改项目的模板

    如何在Sitecore CMS中创建项目后更改项目的模板. 在创建项目时选择了错误的模板,或者创建了新模板并将现有项目更新为新模板时,这非常有用.   警告! 更改模板时要小心.如果原始模板具有不在新 ...

  3. chromedriver 全屏 翻页 错误

    from selenium import webdriver from selenium.common.exceptions import TimeoutException, StaleElement ...

  4. quick player no exit

    QuickXDev插件自动升级后player no exist 昨晚上QuickXDev插件运行还ok,今天打开电脑启动sublime text2后,右键run with player提示player ...

  5. kali 创建快捷方式的方法

    Kali应用程序快捷方式分析 kali默认使用Gnome桌面环境,所以给kali添加应用程序快捷方式就是给Gnome添加应用快捷方式. 在/usr/share/applications目录下有很多的. ...

  6. jsp页面报错 javax.servlet cannot be resolved to a type

    需要引入 Tomcat 中的两个 jar 包: servlet-api jsp-api.jar

  7. 什么是Satoshi?和比特币中本聪有什么关系?

    Satoshi Nakamoto(中本聪)是发起比特币和原始比特币客户端创建者.不过,我经常听到“Satoshi ”这个词,好像它是一个货币单位. 什么是Satoshi呢?Satoshi是0.0000 ...

  8. 实现私有化(Pimpl) --- QT常见的设计模式

    转载自:http://blog.sina.com.cn/s/blog_667102dd0100wxbi.html 一.遇到的问题 1.隐藏实现 我们在给客户端提供接口的时候只希望能暴露它的接口,而隐藏 ...

  9. [转载]oracle的加密和解密

    加密函数 create or replace function encrypt_des(p_text varchar2, p_key varchar2) return varchar2 isv_tex ...

  10. 怎样从外网访问内网SQLServer数据库?

    本地安装了一个SQLServer数据库,只能在局域网内访问到,怎样从外网也能访问到本地的SQLServer数据库呢?本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动SQLServer数据 ...