杂题选谈
有一种人生中最后一篇杂题的感觉,尽量还有下一篇吧
发现自己写的主题虽然 Linux 下看起来非常美观,但是 Windows 下非常丑陋(微软雅黑我喜欢你),希望还有机会修掉这个 bug!
“上一届的女生也是抱着‘感觉自己实在算不上强,只能寄希望于下一个年级的女生因为还没到高二没有警惕了!’的心情上考场的吗?”
唉!妄想症又在骚扰我了!
“跳ねた電気で脳裏を満たして”,用神经元的电信号填满脑袋吧…… 空を満たして完播率 100%…… 果然是这样吗,听到对味的歌之后接下来若干天都舍不得跳
只有 Dopping Dance By STEAKA & White Mind By Blue 直至目前完播率 100%……
现在就怀念可以轻松打出直角引号的 Linux 了。
怎么忘了 AC 自动机可以干啥了,明明昨天还记得
越是这种时候越是慌张。耳机里播着林田匠的 DOEs,或许这就是 John Doe 的写照吧。
好在我还有自己的博客。?怎么看不懂。?怎么博客里也没写可以干啥。
小雷!lhy 是很好的 lhy。大的那个 lhy,不是小的那个 lhy……
那这么说 lhy 岂不是应该叫大雷。大雷一律 0 分(哈气)
你怎么摘我耳机啊,旮旯给木里不是这样的!无妨,摘了耳机我也能跳ねた電気で脳裏を満たして。
A - 销售基因链 / Selling RNA Strands
https://www.luogu.com.cn/problem/P9196
-
很容易想到 ACAM 的做法,显然此处每次询问的后缀是模式串,故离线下来建 ACAM
记录每个初始串对于每个模式串的匹配结果,DSU on tree 即可单 log
-
接下来在 Trie 上跑前缀统计,更简单的可以在 DSU 时就统计一下。复杂度 \(O(n\log n)\)。但是糖丸了!
-
正确的 AC 自动机做法是,考虑到前后缀是分开的很难受,把询问的
P和Q写成Q#P加入自动机,再用S#S匹配即可复杂度线性而且非常好实现。糖丸了!
#include <bits/stdc++.h>
const int maxn = 5e6 + 5;
int T[maxn][5], fail[maxn], cnt[maxn], deg[maxn], tot;
int tab(char t) {
switch (t) {
case 'A':
return 0;
case 'C':
return 1;
case 'G':
return 2;
case 'U':
return 3;
}
return 4;
}
int ins(std::string &s) {
int p = 0;
for (auto i : s) {
if (!T[p][tab(i)])
T[p][tab(i)] = ++tot;
p = T[p][tab(i)];
}
return p;
}
int main() {
#ifdef ONLINE_JUDGE
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr), std::cout.tie(nullptr);
#else
std::freopen(".in", "r", stdin);
std::freopen(".out", "w", stdout);
auto stime = std::chrono::steady_clock::now();
#endif
int n, m;
std::cin >> n >> m;
std::vector<std::string> s(n + 1);
for (int i = 1; i <= n; ++i) {
std::cin >> s[i];
s[i] = s[i] + '#' + s[i];
}
std::vector<int> tail(m + 1);
for (int i = 1; i <= m; ++i) {
std::string p, q;
std::cin >> p >> q, p = q + '#' + p;
tail[i] = ins(p);
}
{
std::queue<int> q;
for (int i = 0; i < 5; ++i)
if (T[0][i])
q.push(T[0][i]);
for (; !q.empty(); ) {
int u = q.front();
q.pop();
for (int i = 0; i < 5; ++i)
if (T[u][i]) {
int v = T[u][i];
fail[v] = T[fail[u]][i];
++deg[T[fail[u]][i]];
q.push(v);
}
else
T[u][i] = T[fail[u]][i];
}
}
for (int i = 1; i <= n; ++i) {
int p = 0;
for (auto j : s[i]) {
p = T[p][tab(j)];
++cnt[p];
}
}
{
std::queue<int> q;
for (int i = 0; i <= tot; ++i)
if (!deg[i])
q.push(i);
for (; !q.empty(); ) {
int u = q.front();
q.pop(), cnt[fail[u]] += cnt[u];
if (!--deg[fail[u]])
q.push(fail[u]);
}
}
for (int i = 1; i <= m; ++i)
std::cout << cnt[tail[i]] << '\n';
#ifndef ONLINE_JUDGE
std::cerr << std::fixed << std::setprecision(6) << std::chrono::duration<double>(std::chrono::steady_clock::now() - stime).count() << "s\n";
#endif
return 0;
}
Balance
https://www.luogu.com.cn/problem/P9731
给定 \(n\times m\) 的二维数组 \(a_{i,j}\),且 \(1\le a_{i,j}\le k\)。你需要重排每一行,使得:
- 对于每个 \(1\le c\le k\),都能找到一个 \(v_c\),使得每一列中,\(c\) 的出现次数要么为 \(v_c\),要么为 \(v_c+1\)。
输出任意合法重排后数组。
\(1\le n,m,k\le 10^5\),\(n\times m\le 5\times 10^5\),且 \(m\) 为 \(2\) 的次幂。
这题你咋做过了还不会啊.jpg
-
考虑 \(m=2\) 的情况,则需要给每列两个点决定先后。
二选一问题考虑连边,惊讶地发现转化为度数问题:如果认为被指向的点排在前面,那么要求 \(\forall \,x,|in_x-out_x|\le 1\)。
这其实是一个欧拉回路问题,(由于有度数为奇的点,建一个虚点连向这些点即可),结合定义思考一下易证。
-
考虑分治解题。由于分治到 \(m=2\) 时总是有解,其实是非常宽松的,只需要保证左右两边拼得起来即可。钦定左右两边 \(x\) 的出现次数不超过 \(1\) 即可保证这件事。
下一步,怎么保证每个数在左右两边的出现次数都不超过 \(1\) 呢?仍然考虑用欧拉回路解决,发现限制是由行带来的,用行当点,与行内元素值连边即可。
-
复杂度 \(O(nm\log m)\),记得写当前弧优化说是。
#include <bits/stdc++.h>
namespace fastIO {
const int LEN = (1 << 20);
#ifdef ONLINE_JUDGE
int nec(void) {
static char buf[LEN], *p = buf, *e = buf;
if (p == e) {
e = buf + fread(buf, 1, LEN, stdin);
if (e == buf) return EOF;
p = buf;
}
return *p++;
}
#else
#define nec getchar
#endif
bool read(int &x) {
x = 0;
bool f = 0;
char ch = nec();
while (ch < '0' || ch > '9') {
if (ch == EOF) return 0;
if (ch == '-') f = 1;
ch = nec();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = nec();
}
if (f) x = -x;
return 1;
}
void print(int x) {
if (x < 0)
putchar('-'), x = -x;
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
return;
}
void print(int x, char ch) {
print(x), putchar(ch);
return;
}
} using namespace fastIO;
int main() {
#ifdef ONLINE_JUDGE
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
freopen("abstruse.in", "r", stdin);
freopen("abstruse.out", "w", stdout);
#else
freopen(".in", "r", stdin);
freopen(".out", "w", stdout);
#endif
int n, m, k;
read(n), read(m), read(k);
std::vector<std::vector<int> > a(n + 1, std::vector<int> (m + 1));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
read(a[i][j]);
std::vector<int> to(k + n + 1), tag(n * m + n + k + 1);
std::vector<std::vector<std::pair<int, int> > > g(k + n + 1);
std::function<void(int, int)> calc = [&](int l, int r) {
if (l + 1 == r) {
for (int i = 1; i <= n; ++i) {
g[a[i][l]].emplace_back(a[i][r], i);
g[a[i][r]].emplace_back(a[i][l], i);
}
int cnt = n;
for (int i = 1; i <= n; ++i) {
if ((int)g[a[i][l]].size() & 1)
g[0].emplace_back(a[i][l], ++cnt), g[a[i][l]].emplace_back(0, cnt);
if ((int)g[a[i][r]].size() & 1)
g[0].emplace_back(a[i][r], ++cnt), g[a[i][r]].emplace_back(0, cnt);
}
std::function<void(int)> DFS = [&](int x) {
for (int i = to[x]; i < (int)g[x].size(); i = to[x]) {
to[x] = i + 1;
auto [v, id] = g[x][i];
if (!tag[id]) {
tag[id] = 1;
if (x && v)
a[id][l] = x, a[id][r] = v;
DFS(v);
}
}
return;
};
DFS(0);
for (int i = 1; i <= n; ++i)
DFS(a[i][l]), DFS(a[i][r]);
to[0] = 0, g[0].clear();
for (int i = 1; i <= n; ++i) {
to[a[i][l]] = 0, g[a[i][l]].clear();
to[a[i][r]] = 0, g[a[i][r]].clear();
}
std::fill(tag.begin() + 1, tag.begin() + cnt + 1, 0);
return;
}
int mid = (l + r) >> 1, cnt = 0;
std::vector<std::vector<std::pair<int, int> > > g(k + n + 1);
for (int i = 1; i <= n; ++i)
for (int j = l; j <= r; ++j) {
g[a[i][j]].emplace_back(i + k, ++cnt);
g[i + k].emplace_back(a[i][j], cnt);
}
for (int i = 1; i <= n; ++i)
for (int j = l; j <= r; ++j)
if ((int)g[a[i][j]].size() & 1)
g[0].emplace_back(a[i][j], ++cnt), g[a[i][j]].emplace_back(0, cnt);
std::vector<int> L(n + 1, l - 1), R(n + 1, r + 1);
std::function<void(int)> DFS = [&](int x) {
for (int i = to[x]; i < (int)g[x].size(); i = to[x]) {
to[x] = i + 1;
auto [v, id] = g[x][i];
if (!tag[id]) {
tag[id] = 1;
if (x && v) {
if (v <= k)
a[x - k][++L[x - k]] = v;
else
a[v - k][--R[v - k]] = x;
}
DFS(v);
}
}
return;
};
DFS(0);
for (int i = 1; i <= n; ++i)
DFS(i + k);
for (int i = 1; i <= n; ++i)
for (int j = l; j <= r; ++j)
DFS(a[i][j]);
to[0] = 0, g[0].clear();
for (int i = 1; i <= n; ++i)
to[i + k] = 0, g[i + k].clear();
for (int i = 1; i <= n; ++i)
for (int j = l; j <= r; ++j)
to[a[i][j]] = 0, g[a[i][j]].clear();
std::fill(tag.begin() + 1, tag.begin() + cnt + 1, 0);
calc(l, mid), calc(mid + 1, r);
return;
};
calc(1, m);
for (int i = 1; i <= n; ++i, putchar('\n'))
for (int j = 1; j <= m; ++j)
print(a[i][j], ' ');
return 0;
}
—— · EOF · ——
真的什么也不剩啦 😖

浙公网安备 33010602011771号