传送门

题意:

对给定字符串\(s\),求其第\(k\)小子串,重复串被计入以及不被计入这两种情况都需考虑。

思路:

首先构建后缀自动机,之后就考虑在后缀自动机上\(dp\)。

我们知道如果要考虑重复串,那么就会与一个结点的\(endpos\)集合的大小有关,对于一条边\((u,v)\),如果结点\(u\)的\(endpos\)集合大小为\(x\),那么就说明从\(u\)出发到达\(v\),会多出\(x\)种选择。

如果不考虑重复串,直接强制集合大小为\(1\)即可。

之后逆着拓扑序\(dp\)就行,求出从每个结点出发的子串个数。

最后求第\(k\)小的时候,有一些细节需要注意一下,比如从\(u\)到\(v\),\(k\)应该减去\(|endpos(v)|\),因为现在的字符串会有\(|endpos(v)|\)个。

感觉后缀自动机好神奇...好多的性质以及用法...

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
struct node{
int ch[26];
int len, fa;
node(){memset(ch, 0, sizeof(ch)), len = 0;}
}dian[N];
int last = 1, tot = 1;
ll f[N], sum[N];
int n, k, op;
char s[N];
int c[N], a[N];
void add(int c) {
int p = last;
int np = last = ++tot;
dian[np].len = dian[p].len + 1;
f[np] = 1;
for(; p && !dian[p].ch[c]; p = dian[p].fa) dian[p].ch[c] = np;
if(!p) dian[np].fa = 1;
else {
int q = dian[p].ch[c];
if(dian[q].len == dian[p].len + 1) dian[np].fa = q;
else {
int nq = ++tot; dian[nq] = dian[q];
dian[nq].len = dian[p].len + 1;
dian[q].fa = dian[np].fa = nq;
for(; p && dian[p].ch[c] == q; p = dian[p].fa) dian[p].ch[c] = nq;
}
}
}
void dfs(int u) {
if(k <= 0) return;
for(int i = 0; i < 26; i++) {
int v = dian[u].ch[i];
if(k > sum[v]) k -= sum[v];
else {
cout << char(i + 'a');
k -= f[v];
dfs(v);
return;
}
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> s + 1 >> op >> k;
int n = strlen(s + 1);
for(int i = 1; i <= n; i++) add(s[i] - 'a');
for(int i = 1; i <= tot; i++) c[dian[i].len]++;
for(int i = 1; i <= tot; i++) c[i] += c[i - 1];
for(int i = 1; i <= tot; i++) a[c[dian[i].len]--] = i;
for(int i = tot; i; i--) {
if(op) f[dian[a[i]].fa] += f[a[i]];
else f[a[i]] = 1;
}
f[1] = 0;
//长度从大到小,逆着拓扑序
//每个结点的next指针指向的点长度肯定不小于它
for(int i = tot; i >= 1; i--) {
sum[a[i]] = f[a[i]];
for(int j = 0; j < 26; j++) {
int v = dian[a[i]].ch[j];
if(v) sum[a[i]] += sum[v];
}
}
if(sum[1] < k) cout << -1;
else dfs(1);
return 0;
}

[TJOI2015]弦论(后缀自动机)的更多相关文章

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

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

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

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

  3. [bzoj3998][TJOI2015]弦论-后缀自动机

    Brief Description 给定一个字符串, 您需要求出他的严格k小子串或非严格k小子串. Algorithm Design 考察使用后缀自动机. 首先原串建SAM, 然后如果考察每个状态代表 ...

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

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

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

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

  6. 【bzoj3998】[TJOI2015]弦论 后缀自动机+dp

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

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

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

  8. [TJOI2015]弦论(后缀自动机)

    /* 一道在树上乱搞的题目 建立出parent树来, 然后就能搞出每个节点往后能扩展出几个串, 至于位置不同算同一个的话就强制让right集合大小为1即可 然后在树上类比权值线段树找第k大26分统计一 ...

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

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

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

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

随机推荐

  1. shell 脚本 for,while,case 语句详解及案例

    ################for循环语句的结构#############使用for循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量值用完退出循环. ...

  2. asp.net mvc移除X-AspNet-Version、X-AspNetMvc-Version、Server

    asp.net mvc程序部署到IIS,,返回的HTTP头中包含Server, X-Powered-By, 和 X-AspNet-Version.X-AspNet-Version信息. 这些信息有时给 ...

  3. Elasticsearch由浅入深(十一)内核原理

    倒排索引组成结构以及索引不可变原因 对于倒排索引是非常适合用来进行搜索的它的结构:(1)包含这个关键词的document list(2)包含这个关键词的所有document的数量:IDF(invers ...

  4. Visual Studio 调试系列5 检查变量(使用自动窗口和局部变量窗口)

    系列目录     [已更新最新开发文章,点击查看详细] 在调试时,“自动变量”和“局部变量”窗口会显示变量值. 仅在调试会话期间,这两个窗口才可用. “自动变量”窗口显示当前断点周围使用的变量. “局 ...

  5. DataSet 反射转换成 List<T>

    /// <summary> /// DataSet转换成指定返回类型的实体集合 /// </summary> /// <typeparam name="T&qu ...

  6. (四)golang--注意事项

    以.go为结尾: 执行入口是main()函数: 区分大小写: Go方法由一条条语句构成,每个语句后不需要加问号: Go编译器是一行行进行编译的,一行不能写多条语句: go语言定义的变量或者import ...

  7. Python学习教程(一)自学资源分享

    Python 可以用来做什么? 在我看来,基本上可以不负责任地认为,Python 可以做任何事情.无论是从入门级选手到专业级选手都在做的爬虫,还是Web 程序开发.桌面程序开发还是科学计算.图像处理, ...

  8. AtomicReference示例

    对引用类型的原子性操作 /** * *对引用变量的原子操作 note: *在java中对引用类型的变量,赋值是原子性的,为什么还要有atomicReference,假如要对一个引用类型进行比较,设置等 ...

  9. flutter-初识(基础语法)

    前言:笔者学过 java,刚刚接触 flutter,记录下基本的一些语法. 一.认识Flutter Flutter 是 google 推出的,使用的 Dart 语言,它可以跨平台实现 Android ...

  10. [4]Hexo静态博客背景及界面显示优化配置

    示例预览:我的主页 前提预设: [3]hexo+github搭建个人博客的主题配置 [2]hexo+github搭建个人博客的简单使用 [1]hexo+github搭建个人博客的过程记录 背景图片添加 ...