260806 康复性训练记录

情况

这次模拟赛只有三个题,把签到题去掉了。因为我太菜了,后面的三个模板题赛前都没做过。

总结一下:模板大赛能做不出 \(\frac23\) 也是挺厉害。

# A B C D
S - 100 10 0

B

题目:P5340 [TJOI2019] 大中锋的游乐场

\(n\) 个点 \(m\) 条边的无向图中有 \(a\) 个 A 类点和 \(b\) 个 B 类点(\(a+b=n\)),给定了每个点的种类和两个点 \(s,t\),求 \(s\)\(t\) 的最短路径,使得 \(s\)\(t\) 的过程中 A 类点与 B 类点的数量之差任意时刻不能超过 \(k\)

分层图最短路。跑一个 Dijkstra 就解决了,难度约等于 NOI 2025 D1T1 机器人。

简单来说,记路径上两类点数之差为 \(p\),对边进行松弛时有 \(dis[v][p_u+<type_v>]\leftarrow dis[u][p_u]+w\)

给到普及+/提高(旧标准)。

#include <bits/stdc++.h>
using namespace std;
#define gc getchar
template<typename T> void read(T &x) {
    char c = gc(); int f = 1; x = 0;
    while (!isdigit(c)) f = (c == '-' ? -f : f), c = gc();
    while (isdigit(c)) x = (x << 3) + (x << 1) + c - '0', c = gc();
    x *= f;
}
template<typename T, typename ... Args> void read(T &x, Args& ... args) {read(x); read(args...);}
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define lll __int128
#define rep(i, s, t) for(ll i=(s);i<=(t);i++)
#define per(i, s, t) for(ll i=(s);i>=(t);i--)
template<typename T> void chkmx(T &x, const T &y) {x = max(x, y);}
template<typename T> void chkmn(T &x, const T &y) {x = min(x, y);}
const ll N = 10005, bis = 15;
ll n, m, k, s, t, a[N], dis[N][30], vis[N][30];
struct edge {
    ll to, w;
};
vector<edge> g[N];
struct node {
    ll v, k, w;
};
const bool operator <(const node &x, const node &y) {return x.w > y.w;}
priority_queue<node> q;
void dijkstra(int st) {
    dis[st][bis + a[st]] = 0;
    q.push({st, a[st], 0});
    while (!q.empty()) {
        auto [u, val, l] = q.top();
        q.pop();
        if (vis[u][bis + val]) continue;
        vis[u][val] = 1;
        // cout << u << ' ' << val << ' ' << l << '\n';
        for (auto [v, w] : g[u]) {
            // cout << u << ":" << v << '\n';
            if (a[v] + val <= k && a[v] + val >= -k) {
                // cout << u << ">" << v << '\n';
                if (dis[v][bis + val + a[v]] > dis[u][bis + val] + w) {
                    // cout << u << "->" << v << '\n';
                    dis[v][bis + val + a[v]] = dis[u][bis + val] + w;
                    q.push({v, val + a[v], dis[v][bis + val + a[v]]});
                }
            }
        }
    }
}
void pd() {
    read(n, m, k);
    rep(i, 1, n) g[i].clear();
    rep(i, 1, n) {
        read(a[i]);
        a[i] = (a[i] == 2) ? 1 : -1;
    }
    rep(i, 1, m) {
        int u, v, w;
        read(u, v, w);
        g[u].push_back({v, w});
        g[v].push_back({u, w});
    }
    read(s, t);
    rep(i, 1, n) rep(j, 0, 29) dis[i][j] = 1e18, vis[i][j] = 0;
    dijkstra(s);
    ll ans = 1e18;
    rep(j, 0, 29) ans = min(ans, dis[t][j]);
    if (ans < 1e17) printf("%lld\n", ans);
    else printf("-1\n");
}
int main() {
    int _; read(_); while (_--)
    pd();
    return 0;
}

C

题目:P4111 [HEOI2015] 小 Z 的房间

\(n\times m\) 的网格图,一开始没有连边。你需要上下左右连边,使得除输入给出的禁止连边的点外,网格图形成一棵树。求连边方案数 \(\mod 1000000000\)

这道题是矩阵树定理的模板题,这是一种可以用于求无/有向图生成树数量的算法。具体请查阅 OI-Wiki 等互联网公开资料。唯一需要注意的是,本题的“墙”(不能连边的点)不要给点赋编号,或者将此类点连接或仅连接到某个固定的点(如 \((1,1)\)),防止因为孤立点导致生成树计数为 \(0\)

涉及到省选/NOI−的知识点。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 605, mod = 1e9;
int n, a[N][N];
int m;
char c[N][N];
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
long long Gauss(int n){
    long long ans = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            while (a[j][i]) {
                long long t = a[i][i] / a[j][i];
                for (int k = i; k <= n; k++) a[i][k] = (a[i][k] - t * a[j][k] % mod + mod) % mod;
                swap(a[i], a[j]);
                ans = -ans;
            }
        }
        ans = (ans * a[i][i] % mod + mod) % mod;
    }
    return ans;
}
signed main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            c[i][j] = getchar();
            while (c[i][j] != '.' && c[i][j] != '*') c[i][j] = getchar();
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (c[i][j] == '*') {
                int u = (i - 1) * m + j;
                int v = (1 - 1) * m + 1;
                a[u][v] = (a[u][v] - 1) % mod;
                a[v][u] = (a[v][u] - 1) % mod;
                a[v][v] = (a[v][v] + 1) % mod;
                a[u][u] = (a[u][u] + 1) % mod;
                continue;
            }
            for (int k = 0; k <= 3; k++) {
                int ni = i + dir[k][0], nj = j + dir[k][1];
                if (ni <= n && ni >= 1 && nj <= m && nj >= 1) {
                    if (c[ni][nj] == '*') continue;
                    int u = (i - 1) * m + j;
                    int v = (ni - 1) * m + nj;
                    a[u][v] = (a[u][v] - 1) % mod;
                    // a[v][u] = (a[v][u] - 1) % mod;
                    // a[v][v] = (a[v][v] + 1) % mod;
                    a[u][u] = (a[u][u] + 1) % mod;
                }
            }
        }
    }
    n = (n - 1) * m + m - 1;
    cout << Gauss(n) << '\n';
    return 0;
}

D

题目:P3733 [HAOI2017] 八纵八横
详见稍后发布的解题报告。

posted @ 2026-08-06 16:47  cwkapn  阅读(3)  评论(0)    收藏  举报