2023.12.31做题纪要
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;
}
P2463 [SDOI2008] Sandy 的卡片
\(SAM\) 版:是个板子题???但是要先学会 \(SAM\) 求 \(LCS\)。
但是我有个地方少取了个 \(min\) 调了半天QAQ。
阴天
#include <bits/stdc++.h>
const int MAXN = 5e3;
int N;
class Suffix_Automaton {
private:
int root, tot, last;
std::map<short, int> child[MAXN];
int length[MAXN], link[MAXN];
int barrel[MAXN][1100];
public:
int string[MAXN];
Suffix_Automaton() {
root = tot = last = 1;
}
void Insert(int c) {
int p = last, newP = ++ tot;
last = newP;
length[newP] = length[p] + 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;
child[newQ] = 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];
}
}
}
}
void Mate(int rank, int *array, int n) {
int now = 1, len = 0;
for (int i = 1; i <= n; ++ i) {
int next = array[i];
while (now && !child[now][next]) {
now = link[now];
len = length[now];
}
if (now) {
len ++;
now = child[now][next];
barrel[now][rank] = std::max(barrel[now][rank], len);
}
else {
now = 1;
len = 0;
}
}
}
int degree[MAXN];
void Build() {
for (int i = 1; i <= tot; ++ i)
degree[link[i]] ++;
}
int check(int now) {
int result = 1e9;
for (int i = 2; i <= N; ++ i) {
if (!barrel[now][i])
return 0;
result = std::min(result, barrel[now][i]);
}
return result;
}
int Update() {
std::queue<int> queue;
for (int i = 1; i <= tot; ++ i)
if (!degree[i])
queue.emplace(i);
while (queue.size()) {
int now =queue.front();
int to = link[now];
queue.pop();
for (int i = 2; i <= N; ++ i) {
barrel[to][i] = std::max(std::min(length[to], barrel[now][i]), barrel[to][i]);
barrel[to][i] = std::min(length[to], barrel[to][i]);
}
degree[to] --;
if (!degree[to])
queue.emplace(to);
}
int result = 0;
for (int i = 1; i <= tot; ++ i)
result = std::max(result, check(i));
return result + 1;
}
}sam;
int a[1100], differ[1100];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> N;
for (int i = 1, M; i <= N; ++ i) {
std::cin >> M;
for (int j = 1; j <= M; ++ j) {
std::cin >> a[j];
if (j >= 2) {
differ[j - 1] = a[j] - a[j - 1];
}
}
if (i == 1)
for (int j = 1; j <= M - 1; ++ j)
sam.Insert(differ[j]);
else
sam.Mate(i, differ, M - 1);
}
sam.Build();
std::cout << sam.Update() << '\n';
return 0;
}