TJOI2015 弦论
身为彩笔的我觉得这道题还不错???对于新学的我来说挺考验对 \(SAM\) 的理解??
要用一个类似洛谷 \(SAM\) 板子题的数组来记录每个节点的 \(right(endpos)\) 集合的大小。
最后维护一下就行了。主要难在证明。
晴天
#include <bits/stdc++.h>
const int MAXN = 3 * (5e5 + 100);
int N, T, K;
char ch[MAXN];
class Suffix_Automaton {
public:
int repeat[MAXN];
private:
void Insert(int c) {
int p = last, newP = ++ tot;
last = newP;
length[newP] = length[p] + 1;
repeat[newP] = 1;
while (p && !child[p][c]) {
child[p][c] = newP;
p = link[p];
}
if (!p) {
link[newP] = root;
}
else {
int q = child[p][c];
if (length[q] == length[p] + 1) {
link[newP] = q;
}
else {
int newQ = ++ tot;
memcpy(child[newQ], child[q], sizeof child[q]);
link[newQ] = link[q];
link[q] = link[newP] = newQ;
length[newQ] = length[p] + 1;
while (p && child[p][c] == q) {
child[p][c] = newQ;
p = link[p];
}
}
}
}
public:
char string[MAXN];
int tot, last, root;
int child[MAXN][27], link[MAXN], length[MAXN];
int count[MAXN];
Suffix_Automaton() {
root = tot = last = 1;
}
void Treat() {
int N = strlen(string + 1);
for (int i = 1; i <= N; ++ i)
Insert(string[i] - 'a' + 1);
}
std::vector<int> son[MAXN];
void Build() {
for (int i = 1; i <= tot; ++ i) {
son[link[i]].emplace_back(i);
}
}
void Dfs(int now) {
for (const int &iter: son[now]) {
Dfs(iter);
repeat[now] += repeat[iter];
}
}
}sam;
bool visit[MAXN];
int Dfs(int now) {
if (visit[now])
return sam.count[now];
if (T == 0)
sam.repeat[now] = 1;
sam.count[now] = sam.repeat[now];
visit[now] = true;
for (int i = 1; i <= 26; ++ i) {
if (!sam.child[now][i])
continue;
sam.count[now] += Dfs(sam.child[now][i]);
}
return sam.count[now];
}
std::vector<char> answer;
void GetAnswer(int now, int rest) {
rest -= sam.repeat[now];
if (rest == 0)
return;
for (int i = 1; i <= 26; ++ i) {
int to = sam.child[now][i];
if (!to)
continue;
if (rest - sam.count[to] <= 0) {
answer.emplace_back('a' + i - 1);
GetAnswer(to, rest);
return;
}
rest -= sam.count[to];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> (sam.string + 1);
std::cin >> T >> K;
sam.Treat();
if (T == 1) {
sam.Build();
sam.Dfs(1);
}
Dfs(1);
GetAnswer(1, K + sam.repeat[1]);
if (!answer.size()) {
std::cout << -1 << '\n';
return 0;
}
for (const char &iter: answer)
std::cout << iter;
std::cout << '\n';
return 0;
}