传送门

题意:

对给定字符串\(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. zr2019暑期高端峰会AB组十测

    郑睿round 1 代码真的好写,还是太笨了,爆零了. 郑睿round_2 好失败,A题真的是日狗了,第一发就可以A的,忘记费用流的反向边也要加一发流量了.哎,我注定是要爆零. 正睿round_3 日 ...

  2. Codeforces Global Round 4 题解

    技不如人,肝败吓疯…… 开场差点被 A 题意杀了,幸好仔细再仔细看,终于在第 7 分钟过掉了. 跟榜.wtf 怎么一群人跳题/倒序开题? 立刻紧张,把 BC 迅速切掉,翻到了 100+. 开 D.感觉 ...

  3. [LeetCode] 381. Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

  4. [LeetCode] 322. Coin Change 硬币找零

    You are given coins of different denominations and a total amount of money amount. Write a function ...

  5. shell之startup

    #!/bin/sh # # # # PROJECT=$ APPWORK_DIR=~/apps/$PROJECT LOGPATH=~/logs/$ LOGFILE=~/logs/$PROJECT/${P ...

  6. c#中怎样取得某坐标点的颜色

    // x,y 分别为x轴,y轴坐标 返回System.Drawing.Color 可以直接显示 public System.Drawing.Color GetPixelColor(int x, int ...

  7. <T>泛型,广泛的类型

    其实早在1999年的JSR 14规范中就提到了泛型概念,知道jdk5泛型的使用才正式发布,在jdk7后,又对泛型做了优化,泛型的推断. 泛型类 public class Pair<T> { ...

  8. enum一个最不像class的class

    enum一个最不像class的classjava枚举类型是jdk5出现的.它的出现主要为了解决一些有特殊意义,已经确定的,长度不会改变的集合. //月份描述 public class Month { ...

  9. KVM 学习笔记

    查看虚拟化环境 (1)查看虚拟机环境 (2)查看kvm模块支持 (3)查看虚拟工具版本 (4)查看网桥

  10. 第一次有人把 5G 讲的这么简单明了

    一个简单且神奇的公式    今天的故事,从一个公式开始讲起.这是一个既简单又神奇的公式.说它简单,是因为它一共只有 3 个字母.而说它神奇,是因为这个公式蕴含了博大精深的通信技术奥秘,这个星球上有无数 ...