题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=3998
题解:

后缀自动机。
当T=0时,
由于在后缀自动机上沿着trans转移,每个串都是互不相同的,
就只需要统计出从每个状态出发,存在多少条不同的路径,即有多少个不同的子串。
这个可以拓扑排序后用DP解决。
转移: $$cnt[p]=\sum_{trans[p][*]=q,q!=0} cnt[q] + 1$$
然后配合cnt[]去dfs即可。
当T=1时,
这时考虑了相同的子串。但是不难发现,
如果沿着trans转移到了一个状态s,
那么s的Right集合大小就表示了这个串出现了多少次。
所以沿用上面T=0的做法,只是把DP转移稍稍修改一下:
转移: $$cnt[p]=\sum_{trans[p][*]=q,q!=0} cnt[q] + right[p]$$
(把+1改为+right[p即可],接下来同样是配合cnt[]去dfs。)
(本人代码跑得很慢,2333)

代码:

#include<bits/stdc++.h>
#define MAXN 500005
#define ll long long
using namespace std;
ll cnt[MAXN*3];
struct SAM{
int size;
int maxs[MAXN*3],trans[MAXN*3][26],parent[MAXN*3],right[MAXN*3];
int Newnode(int a,int b){
++size; maxs[size]=a;
memcpy(trans[size],trans[b],sizeof(trans[b]));
return size;
}
int Extend(int last,int x){
static int p,np,q,nq;
p=last; np=Newnode(maxs[p]+1,0);
for(;p&&!trans[p][x];p=parent[p]) trans[p][x]=np;
if(!p) parent[np]=1;
else{
q=trans[p][x];
if(maxs[p]+1!=maxs[q]){
nq=Newnode(maxs[p]+1,q);
parent[nq]=parent[q];
parent[q]=parent[np]=nq;
for(;p&&trans[p][x]==q;p=parent[p]) trans[p][x]=nq;
}
else parent[np]=q;
}
return np;
}
void Build(char *S){
static int p=1,last,tmp[MAXN],order[MAXN*3],len;
memset(trans[0],0,sizeof(trans[0]));
size=0; last=Newnode(0,0); len=strlen(S);
for(int i=0;i<len;i++) last=Extend(last,S[i]-'a'); for(int i=0;i<len;i++) p=trans[p][S[i]-'a'],right[p]++;
for(int i=1;i<=size;i++) tmp[maxs[i]]++;
for(int i=1;i<=len;i++) tmp[i]+=tmp[i-1];
for(int i=1;i<=size;i++) order[tmp[maxs[i]]--]=i;
for(int i=size;i;i--) p=order[i],right[parent[p]]+=right[p];
}
void Count(int t){
static queue<int> Q;
static int in[MAXN*3],order[MAXN*3],ont;
for(int p=1;p<=size;p++)
for(int c=0;c<26;c++) if(trans[p][c])
in[trans[p][c]]++;
Q.push(1);
while(!Q.empty()){
int u=Q.front(); Q.pop(); order[++ont]=u;
for(int c=0;c<26;c++) if(trans[u][c]){
in[trans[u][c]]--;
if(!in[trans[u][c]]) Q.push(trans[u][c]);
}
}
for(int i=size,p;i;i--){
p=order[i]; cnt[p]=p==1?0:t==0?1:right[p];
for(int c=0;c<26;c++) if(trans[p][c])
cnt[p]+=cnt[trans[p][c]];
}
}
}SUF;
void DFS(int p,int k,int t,int from){
static int i;
static char ans[MAXN];
if(p==1) i=0;
else{
ans[i++]=from+'a';
k-=t==0?1:SUF.right[p];
}
if(k<=0) return (void)(ans[i]=0,puts(ans));
for(int c=0;c<26;c++){
if(k<=cnt[SUF.trans[p][c]]){
DFS(SUF.trans[p][c],k,t,c);
break;
}
k-=cnt[SUF.trans[p][c]];
}
}
int main(){
int T,K;
static char S[MAXN];
scanf("%s%d%d",S,&T,&K);
SUF.Build(S);
SUF.Count(T);
// printf("%lld\n",cnt[1]);
if(K<=cnt[1]) DFS(1,K,T,0);
else puts("-1");
return 0;
}

  

●BZOJ 3998 [TJOI2015]弦论的更多相关文章

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

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

  2. BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串

    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...

  3. bzoj 3998 [TJOI2015]弦论——后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 相同子串算多个的话,先求好 right ,然后求一个 sm 表示走到这个点之后有几种走 ...

  4. BZOJ 3998 TJOI2015 弦论 后缀自动机+DAG上的dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998 题意概述:对于一个给定长度为N的字符串,求它的第K小子串是什么,T为0则表示不同位置 ...

  5. bzoj 3998: [TJOI2015]弦论【SA+二分||SAM】

    SA的话t==0直接预处理出每个后缀的不同串贡献二分即可,然后t==1就按字典序枚举后缀,然后跳右端点计算和当前后缀的前缀相同的子串个数,直到第k个 不过bzoj上会T #include<ios ...

  6. bzoj 3998: [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  7. BZOJ.3998.[TJOI2015]弦论(后缀自动机)

    题目链接 \(Description\) 给定字符串S,求其第K小子串.(若T=0,不同位置的相同子串算1个:否则算作多个) \(Solution\) 建SAM,处理出对于每个节点,它和它的所有后继包 ...

  8. 【刷题】BZOJ 3998 [TJOI2015]弦论

    Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input 第一行是一个仅由小写英文字母构成的字符串S 第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个. ...

  9. BZOJ 3998 [TJOI2015]弦论 ——后缀自动机

    直接构建后缀自动机. 然后. 然后只需要再后缀自动机的go树上类似二分的方法进行查找即可,实际上是“26分”. 然后遇到了处理right集合的问题,然后觉得在go和parent树上上传都是可以的,毕竟 ...

随机推荐

  1. verilog学习笔记(0)

    assign赋值语句根本不允许出现在always语句块中 位于begin/end块内的多条阻塞赋值语句是串行执行的; 但是多条非阻塞赋值语句却是并行执行的,这些非阻塞赋值语句都会在其中任何一条语句执行 ...

  2. 亚马逊AWS学习——VPC里面几个概念的关系

    VPC中涉及几个概念: VPC 子网 路由表 Internet网关 安全组 今天来讲讲这几个概念之间的关系. 1. VPC 说的就是VPC,当然VPC范围是最大的,VPC即virtual privat ...

  3. javascript中的数组对象

    1.创建数组的三种方式: 1.1 var 数组名=[元素1,元素2,元素3...]; 例如: var arr1=[1,2,3,4]; 1.2 var 数组名=new Array(元素1,元素2,元素3 ...

  4. js window

    window对象: browser object mode :bom对象. bom提供了独立于内容而与浏览器窗口进行交互的对象. bom主要用于管理窗口与窗口之间的通讯,因此其核心对象是window ...

  5. python 字符串的方法

    capitalize() 把字符串的第一个字符改为大写 casefold() 把整个字符串的所有字符改为小写 center(width) 将字符串居中,并使用空格填充至长度 width 的新字符串 c ...

  6. leetcode算法:Island Perimeter

    You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represen ...

  7. Python基础数据类型之集合以及其他和深浅copy

    一.基础数据类型汇总补充 list  在循环一个列表时,最好不要删除列表中的元素,这样会使索引发生改变,从而报错(可以从后向前循环删除,这样不会改变未删元素的索引). 错误示范: lis = [,,, ...

  8. Android 6.0 以后webview不加载图片的问题

    /** * Webview在安卓5.0之前默认允许其加载混合网络协议内容 * 在安卓5.0之后,默认不允许加载http与https混合内容,需要设置webview允许其加载混合网络协议内容 */if ...

  9. Properties文件读写问题

    项目需要在Properties配置文件中设置一些配置属性,其中包含一些中文属性.经过一上午的奋斗终于圆满解决问题. 读取Properties文件所有属性 Map<String, String&g ...

  10. Intent 的两种主要使用方法

    首先建立两个activity界面 Activity1如下 public class MainActivity extends AppCompatActivity { private Button bt ...