k小子串 SPOJ - SUBLEX 2
题意:
求字典序第K大的子串
题解:
先求出后缀自动机对应节点
// 该节点后面所形成的自字符串的总数 然后直接模拟即可
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map> #define pi acos(-1.0)
#define eps 1e-9
#define fi first
#define se second
#define rtl rt<<1
#define rtr rt<<1|1
#define bug printf("******\n")
#define mem(a, b) memset(a,b,sizeof(a))
#define name2str(x) #x
#define fuck(x) cout<<#x" = "<<x<<endl
#define sfi(a) scanf("%d", &a)
#define sffi(a, b) scanf("%d %d", &a, &b)
#define sfffi(a, b, c) scanf("%d %d %d", &a, &b, &c)
#define sffffi(a, b, c, d) scanf("%d %d %d %d", &a, &b, &c, &d)
#define sfL(a) scanf("%lld", &a)
#define sffL(a, b) scanf("%lld %lld", &a, &b)
#define sfffL(a, b, c) scanf("%lld %lld %lld", &a, &b, &c)
#define sffffL(a, b, c, d) scanf("%lld %lld %lld %lld", &a, &b, &c, &d)
#define sfs(a) scanf("%s", a)
#define sffs(a, b) scanf("%s %s", a, b)
#define sfffs(a, b, c) scanf("%s %s %s", a, b, c)
#define sffffs(a, b, c, d) scanf("%s %s %s %s", a, b,c, d)
#define FIN freopen("../in.txt","r",stdin)
#define gcd(a, b) __gcd(a,b)
#define lowbit(x) x&-x
#define IO iOS::sync_with_stdio(false) using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const ULL seed = ;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int maxm = 8e6 + ;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + ;
const int maxn = ; struct Suffix_Automaton {
int last, tot, nxt[maxn << ][], fail[maxn << ];//last是未加入此字符前最长的前缀(整个串)所属的节点的编号
int len[maxn << ];// 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
int sa[maxn << ], c[maxn << ];
int sz[maxn << ];// 被后缀链接的个数,方便求节点字符串的个数
LL num[maxn << ];// 该状态子串的数量
LL maxx[maxn << ];// 长度为x的子串出现次数最多的子串的数目
LL sum[maxn << ];// 该节点后面所形成的自字符串的总数
LL subnum, sublen;// subnum表示不同字符串数目,sublen表示不同字符串总长度
int X[maxn << ], Y[maxn << ]; // Y表示排名为x的节点,X表示该长度前面还有多少个
void init() {
tot = last = ;
fail[] = len[] = ;
for (int i = ; i < ; i++) nxt[][i] = ;
} void extend(int c) {
int u = ++tot, v = last;
len[u] = len[v] + ;
num[u] = ;
for (; v && !nxt[v][c]; v = fail[v]) nxt[v][c] = u;
if (!v) fail[u] = , sz[]++;
else if (len[nxt[v][c]] == len[v] + ) fail[u] = nxt[v][c], sz[nxt[v][c]]++;
else {
int now = ++tot, cur = nxt[v][c];
len[now] = len[v] + ;
memcpy(nxt[now], nxt[cur], sizeof(nxt[cur]));
fail[now] = fail[cur];
fail[cur] = fail[u] = now;
for (; v && nxt[v][c] == cur; v = fail[v]) nxt[v][c] = now;
sz[now] += ;
}
last = u;
//return len[last] - len[fail[last]];//多添加一个子串所产生不同子串的个数
} void get_num() {// 每个节点子串出现的次数
for (int i = ; i <= tot; i++) X[len[i]]++;
for (int i = ; i <= tot; i++) X[i] += X[i - ];
for (int i = ; i <= tot; i++) Y[X[len[i]]--] = i;
for (int i = tot; i >= ; i--) num[fail[Y[i]]] += num[Y[i]];
} void get_maxx(int n) {// 长度为x的子串出现次数最多的子串的数目
get_num();
for (int i = ; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
} void get_sum() {// 该节点后面所形成的自字符串的总数
get_num();
for (int i = tot; i >= ; i--) {
sum[Y[i]] = ;
for (int j = ; j <= ; j++)
sum[Y[i]] += sum[nxt[Y[i]][j]];
}
} void get_subnum() {//本质不同的子串的个数
subnum = ;
for (int i = ; i <= tot; i++) subnum += len[i] - len[fail[i]];
} void get_sublen() {//本质不同的子串的总长度
sublen = ;
for (int i = ; i <= tot; i++) sublen += 1LL * (len[i] + len[fail[i]] + ) * (len[i] - len[fail[i]]) / ;
} void get_sa() { //获取sa数组
for (int i = ; i <= tot; i++) c[len[i]]++;
for (int i = ; i <= tot; i++) c[i] += c[i - ];
for (int i = tot; i >= ; i--) sa[c[len[i]]--] = i;
} int minn[maxn << ], mx[maxn << ];//多个串的最长公共子串
//minn[i]表示多个串在后缀自动机i节点最长公共子串,mx[i]表示单个串的最长公共子串 void match(char s[]) {
mem(mx, );
int n = strlen(s), p = , maxlen = ;
for (int i = ; i < n; i++) {
int c = s[i] - 'a';
if (nxt[p][c]) p = nxt[p][c], maxlen++;
else {
for (; p && !nxt[p][c]; p = fail[p]);
if (!p) p = , maxlen = ;
else maxlen = len[p] + , p = nxt[p][c];
}
mx[p] = max(mx[p], maxlen);
}
for (int i = tot; i; i--)
mx[fail[i]] = max(mx[fail[i]], min(len[fail[i]], mx[i]));
for (int i = tot; i; i--)
if (minn[i] == - || minn[i] > maxx[i]) minn[i] = mx[i];
} void get_kth(int k) {//求出字典序第K的子串
int pos = , cnt;
string s = "";
while (k) {
for (int i = ; i <= ; i++) {
if (nxt[pos][i] && k) {
cnt = nxt[pos][i];
if (sum[cnt] < k) k -= sum[cnt];
else {
k--;
pos = cnt;
s += (char) (i + 'a');
break;
}
}
}
}
cout << s << endl;
}
} sam; char s[maxn];
int Q; int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif
sam.init();
sfs(s + );
int n = strlen(s + );
for (int i = ; i <= n; i++) sam.extend((s[i] - 'a'));
sam.get_sum();
sfi(Q);
while (Q--) {
int k;
sfi(k);
sam.get_kth(k);
}
#ifndef ONLINE_JUDGE
cout << "Totle Time : " << (double) clock() / CLOCKS_PER_SEC << "s" << endl;
#endif
return ;
}
k小子串 SPOJ - SUBLEX 2的更多相关文章
- HDU 5008 求第k小子串
本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息.由于题目要求子串起始下标尽可能小.所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串 ...
- 「BZOJ3998」[TJOI2015] 弦论(第K小子串)
https://www.lydsy.com/JudgeOnline/problem.php?id=3998 Description 对于一个给定长度为N的字符串,求它的第K小子串是什么. Input ...
- [TJOI2015]弦论(第k小子串)
题意: 对于一个给定的长度为n的字符串,求出它的第k小子串. 有参数t,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个. 题解: 首先,因为t的原因,后缀数组较难实现, ...
- SPOJ SUBLEX 求第k小子串
题目大意: 对于一个给定字符串,找到其所有不同的子串中排第k小的子串 先构建后缀自动机,然后我们可以将整个后缀自动机看做是一个DAG图,那么我们先进行拓扑排序得到 *b[N] 对于每个节点记录一个sc ...
- Lexicographical Substring Search (spoj7259) (sam(后缀自动机)+第k小子串)
Little Daniel loves to play with strings! He always finds different ways to have fun with strings! K ...
- BZOJ3998 弦论 【SAM】k小子串
BZOJ3998 弦论 给一个字符串,问其第\(K\)小字串是什么 两种形式 1.不同起始位置的相同串只算一次 2.不同起始位置的相同串各算一次 首先建\(SAM\) 所有串的数量就是\(SAM\)中 ...
- BZOJ 3998: [TJOI2015]弦论 后缀自动机 后缀自动机求第k小子串
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 后缀自动机应用的一个模板?需要对len进行一个排序之后再统计每个出现的数量,维护的是以该字符串 ...
- SPOJ - SUBLEX 【后缀自动机】
题目 求第K小子串 题解 建好SAM后,拓扑排序,反向传递后面所形成的串的数量 最后从根开始,按照儿子形成串的数量与k比较走就好了 #include<iostream> #include& ...
- hdu 5008 查找字典序第k小的子串
Boring String Problem Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Ot ...
随机推荐
- python作业/练习/实战:生成随机密码
作业要求1.写一个函数,函数的功能是生成一批密码,存到文件里面 def gen_password(num): #num代表生成多少条密码2.密码复杂度要求 1)长度在,8-16位之间 2)密码必须包括 ...
- Linux下安装JDK(小白教程)
一. 选择与下载jdk 1. 官网上按照自己的系统版本下载相应jdk,因为我的LINUX(testbest)是32位的,所以我下载32位的jdk. 2. 官网下载地址:http://www. ...
- 发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下
发布 Vant - 高效的 Vue 组件库,再造一个有赞移动商城也不在话下:https://segmentfault.com/a/1190000011377961 vantUI框架在vue项目中的应用 ...
- spark性能调优04-算子调优
1.使用MapPartitions代替map 1.1 为什么要死使用MapPartitions代替map 普通的map,每条数据都会传入function中进行计算一次:而是用MapPartitions ...
- 一个完整实用的axios封装
1.先引入 import axios from 'axios' import qs from 'qs'import router from '../router'; import store from ...
- buuctf zip伪加密
平时伪加密总是依赖osx,这道题无法直接解压,所以研究一下伪加密先放两张图(图是偷的)一般在压缩源文件数据区全局方式位标记处,真加密为 09 00,伪加密为00 00,而后面将压缩源文件目录区全局方式 ...
- myeclipse中使用maven插件的时候,报错-Dmaven.multiModuleProjectDirectory system propery is not set.
-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable a ...
- postgresql 备份数据库结构
--只备份结构pg_dump -U postgres -d grgzpt -f D:\dump.sql -s --备份结构和数据pg_dump -U postgres -d grgzpt -f D:\ ...
- linux学习总结--linux100day(day1)
写在前面:我是一名在学习linux的小学生,最近在学习python时,我的老师推荐了github上的一本教材“python100day”,100day里面的内容由浅入深,且都具备详细的例子,对于我这个 ...
- koa2 使用 async 、await、promise解决异步的问题
koa代码编写上避免了多层的嵌套异步函数调用 async await来解决异步 - async await 需要依赖于promise 三主角: __函数前面 async, 内部才能await,要想aw ...