多校杂题
2025-09-03
暂无标签

还算能做


A. Itinerary

https://www.luogu.com.cn/problem/P12195

  • 画个图可以发现当前仅当同时满足:

    • 给定的欧拉序子序列合法,即按照给定的顺序,任意一条边不被经过超过两次;为路径上的边按照经过时的方向打上标记。可以用暴力爬山之类的方法验证,这个过程是线性的。
    • 选定的起点可以到达 \(s_1\),且经过的边要么没有标记,要么标记方向和经过的方向相反。
  • 所以可以从 \(s_1\) 做一遍 DFS,要求不能经过拥有相同方向标记的边即可。

#include <bits/stdc++.h>
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);
    const auto stime = std::chrono::steady_clock::now();
#endif
    int n, m;
    std::cin >> n >> m;
    struct edge { int v, id, ix; };
    std::vector<std::array<int, 2> > tag(n);
    std::vector<std::vector<edge> > g(n + 1);
    for (int i = 1, x, y; i < n; ++i) {
        std::cin >> x >> y;
        g[x].push_back({ y, i, 0 });
        g[y].push_back({ x, i, 1 });
    }
    std::vector<int> dep(n + 1);
    std::vector<edge> fa(n + 1);
    std::function<void(int, int)> DFS = [&](int x, int faa) {
        for (auto [i, id, ix] : g[x])
            if (i != faa) {
                dep[i] = dep[x] + 1;
                fa[i] = { x, id, !ix };
                DFS(i, x);
            }
        return;
    };
    dep[1] = 1, DFS(1, -1);
    std::vector<int> s(m + 1);
    for (int i = 1; i <= m; ++i)
        std::cin >> s[i];
    for (int i = 2; i <= m; ++i) {
        int x = s[i - 1], y = s[i];
        if (dep[x] > dep[y])
            for (; dep[x] > dep[y]; x = fa[x].v) {
                if (tag[fa[x].id][fa[x].ix])
                    goto outo;
                tag[fa[x].id][fa[x].ix] = 1;
            }
        else
            for (; dep[y] > dep[x]; y = fa[y].v) {
                if (tag[fa[y].id][!fa[y].ix])
                    goto outo;
                tag[fa[y].id][!fa[y].ix] = 1;
            }
        for (; x != y; x = fa[x].v, y = fa[y].v) {
            if (tag[fa[x].id][fa[x].ix] || tag[fa[y].id][!fa[y].ix])
                goto outo;
            tag[fa[x].id][fa[x].ix] = 1;
            tag[fa[y].id][!fa[y].ix] = 1;
        }
        continue;
    outo:
        for (int j = 1; j <= n; ++j)
            std::cout << 0 << '\n';
        return 0;
    }
    std::vector<int> res(n + 1);
    DFS = [&](int x, int fa) {
        res[x] = 1;
        for (auto [i, id, ix] : g[x])
            if (i != fa && !tag[id][!ix])
                DFS(i, x);
        return;
    };
    DFS(s[1], -1);
    for (int i = 1; i <= n; ++i)
        std::cout << res[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;
}

B. 2D Conveyer Belt S

https://www.luogu.com.cn/problem/P11454

  • 注意到每个点的出度最多为 1。容易发现一个点是不可用的,当且仅当:

    • 在至少一个环内部;
    • 或者,会到达一个环上的点。
  • 难点在于如何快速找到每次操作后环内部的点。但发现由于每个点出度为 1,不会出现:

    之类让人摸不着头脑的情况。可以考虑找到外层合法的点,倒放 + floodfill 来保证复杂度;不知道有没有更简单的做法。
  • 具体 floodfill 的方式是,对于一个合法的格子,如果其上方有一个方向为 D 的格子,那么上方也是合法的。这个转化是比较重要的。

#include <bits/stdc++.h>
const int dir[][3] = { { 0, -1, 1 }, { 0, 1, 2 }, { -1, 0, 3 }, { 1, 0, 4 } };
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);
    const auto stime = std::chrono::steady_clock::now();
#endif
    int n, q;
    std::cin >> n >> q, n += 2;
    std::vector<std::vector<int> > tag(n + 1, std::vector<int> (n + 1)), a(n + 1, std::vector<int> (n + 1));
    std::vector<std::pair<int, int> > g(q + 1);
    int tot = 0;
    for (int i = 1, x, y; i <= q; ++i) {
        char t;
        std::cin >> x >> y >> t, ++x, ++y;
        g[i] = { x, y };
        if (t == 'L')
            a[x][y] = 2;
        else if (t == 'R')
            a[x][y] = 1;
        else if (t == 'U')
            a[x][y] = 4;
        else
            a[x][y] = 3;
    }
    std::function<void(int, int)> DFS = [&](int x, int y) {
        tag[x][y] = 1, ++tot;
        for (auto [fx, fy, fi] : dir) {
            int nx = x + fx, ny = y + fy;
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= n && !tag[nx][ny] && (!a[nx][ny] || a[nx][ny] == fi))
                DFS(nx, ny);
        }
        return;
    };
    DFS(1, 1);
    std::vector<int> res(q + 1);
    res[q] = n * n - tot;
    for (int i = q; i > 1; --i) {
        auto [x, y] = g[i];
        if (!tag[x][y] && (tag[x][y - 1] || tag[x][y + 1] || tag[x - 1][y] || tag[x + 1][y]))
            DFS(x, y);
        a[x][y] = 0;
        res[i - 1] = n * n - tot;
    }
    for (int i = 1; i <= q; ++i)
        std::cout << res[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;
}

C. 机器人

https://www.luogu.com.cn/problem/P12018

  • 考察题意,

言论