杂题选谈

有一种人生中最后一篇杂题的感觉,尽量还有下一篇吧

发现自己写的主题虽然 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 自动机做法是,考虑到前后缀是分开的很难受,把询问的 PQ 写成 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;
}
posted @ 2025-11-27 11:30  cqbzlym  阅读(1)  评论(0)    收藏  举报