T1:Potions

模拟

代码实现
n, h, x = map(int, input().split())
p = list(map(int, input().split()))
for i in range(n):
    if h+p[i] >= x:
        exit(print(i+1))

T2:MissingNo.

不妨假设丢失的整数不是其中的最小数,然后用 std::set 来找出那个丢失的数即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n;
    cin >> n;
    
    set<int> s;
    rep(i, n) {
        int a;
        cin >> a;
        s.insert(a);
    }
    
    int x = *s.begin();
    while (s.count(x)) ++x;
    
    cout << x << '\n';
    
    return 0;
}

T3:Remembering the Days

暴力枚举

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<array<int, 2>>> g(n);
    rep(i, m) {
        int a, b, c;
        cin >> a >> b >> c;
        --a; --b;
        g[a].push_back({b, c});
        g[b].push_back({a, c});
    }
    
    int ans = 0;
    vector<bool> used(n);
    auto f = [&](auto f, int v, int dist) -> void {
        used[v] = true;
        ans = max(ans, dist);
        for (auto [u, w] : g[v]) {
            if (used[u]) continue;
            f(f, u, dist+w);
        }
        used[v] = false;
    };
    
    rep(i, n) f(f, i, 0);
    
    cout << ans << '\n';
    
    return 0;
}

T4:President

在每个选区,如果通过策反 \(w\) 人就能获得 \(v\) 个议席,那么就变成了背包问题

\(d=\) 青木的议席数 - 高桥的议席数

我们只需让 \(d < 0\),那么高桥就赢了

注意到每次让高桥的议席数 +v,相应的青木的议席数就会 -v,那么 \(d\) 就会减少 \(2v\)

dp[i][j] 表示到第 \(i\) 个选区为止,为了使得 \(\sum v'=j\) 所需要策反的人数的最小值,其中 \(v' = 2v\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;
using P = pair<int, int>;

inline void chmin(ll& a, ll b) { if (a > b) a = b; }

int main() {
    int n;
    cin >> n;
    
    int w = 0;
    vector<P> data;
    rep(i, n) {
        int x, y, z;
        cin >> x >> y >> z;
        int a = max(0, (y-x+1)/2);
        w += z;
        data.emplace_back(a, z*2);
    }
    
    const ll INF = 1e18;
    vector dp(n+1, vector<ll>(w+1, INF));
    dp[0][0] = 0;
    rep(i, n) {
        auto [a, z] = data[i];
        rep(j, w+1) {
            chmin(dp[i+1][j], dp[i][j]);
            chmin(dp[i+1][min(w, j+z)], dp[i][j]+a);
        }
    }
    
    ll ans = dp[n][w];
    cout << ans << '\n';
    
    return 0;
}

T5:Avoid Eye Contact

先找到所有进入别人视线无法而通过的格子,然后 \(\operatorname{bfs}\) 就可以了!

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using P = pair<int, int>;

const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, -1, 0, 1};

int main() {
    int h, w;
    cin >> h >> w;
    
    vector<string> s(h);
    rep(i, h) cin >> s[i];
    
    int si, sj, gi, gj;
    rep(i, h)rep(j, w) {
        if (s[i][j] == 'S') si = i, sj = j, s[i][j] = '.';
        if (s[i][j] == 'G') gi = i, gj = j, s[i][j] = '.';
    }
    
    vector ng(h, vector<bool>(w));
    rep(i, h)rep(j, w) {
        int v = -1;
        if (s[i][j] == '^') v = 0;
        if (s[i][j] == '<') v = 1;
        if (s[i][j] == 'v') v = 2;
        if (s[i][j] == '>') v = 3;
        if (s[i][j] == '#') ng[i][j] = true;
        if (v == -1) continue;
        int ni = i, nj = j;
        while (1) {
            ng[ni][nj] = true;
            ni += di[v]; nj += dj[v];
            if (ni < 0 or nj < 0 or ni >= h or nj >= w) break;
            if (s[ni][nj] != '.') break;
        }
    }
    
    const int INF = 1001001001;
    vector dist(h, vector<int>(w, INF));
    queue<P> q;
    dist[si][sj] = 0; q.emplace(si, sj);
    while (q.size()) {
        auto [i, j] = q.front(); q.pop();
        rep(v, 4) {
            int ni = i+di[v], nj = j+dj[v];
            if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
            if (ng[ni][nj]) continue;
            if (dist[ni][nj] != INF) continue;
            dist[ni][nj] = dist[i][j]+1;
            q.emplace(ni, nj);
        }
    }
    
    int ans = dist[gi][gj];
    if (ans == INF) ans = -1;
    cout << ans << '\n';
    
    return 0;
}

T6:Nim

数位 \(\operatorname{dp}\)

dp[n][f1][f2][f3][r1][r2][r3] 表示满足以下条件的三元组 \((x_1, x_2, x_3)\) 的个数:

  • 对于每个 \(i\)\(0 \leqslant x_i < 2^n\)
  • \(x_1 \oplus x_2 \oplus x_3 = 0\)
  • 对于每个 \(i\)\(x_i\) 是否不超过 \(n\&(2^n-1)\) 的逻辑值为 \(f_i\)
  • 对于每个 \(i\)\(x_i\)\(A_i\) 取模的余数为 \(r_i\)
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;
using mint = modint998244353;

int main() {
    ll n;
    cin >> n;
    n++;
    const int m = 3;
    vector<int> a(m);
    rep(i, m) cin >> a[i];
    
    vector<int> ds;
    while (n) {
        ds.emplace_back(n&1);
        n >>= 1;
    }
    reverse(ds.begin(), ds.end());
    
    using T = tuple<int, bool, bool>;
    using VT = vector<T>;
    map<VT, mint> dp;
    dp[VT(3)] = 1;
    for (int digit : ds) {
        map<VT, mint> pre; swap(dp, pre);
        for (auto [s, num] : pre) {
            rep(b, 1<<m) {
                if (__builtin_parity(b)) continue;
                bool ok = true;
                VT ns;
                rep(i, m) {
                    auto [md, lt, z] = s[i];
                    int nb = b>>i&1;
                    md = (md*2+nb)%a[i];
                    z |= nb;
                    if (!lt and nb > digit) ok = false;
                    lt |= nb < digit;
                    ns.emplace_back(md, lt, z);
                }
                if (ok) dp[ns] += num;
            }
        }
    }
    
    mint ans = dp[VT(3, {0, 1, 1})];
    cout << ans.val() << '\n';
    
    return 0;
}

T7:Rearranging

这题是行和数字匹配的二分图匹配问题,跑 \(m\) 次二分图匹配就能解决问题!

代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector a(n, vector<int>(m));
    rep(i, n)rep(j, m) cin >> a[i][j], a[i][j]--;
    
    int sv = n+n, tv = sv+1;
    mf_graph<int> g(tv+1);
    rep(i, n)rep(j, m) g.add_edge(i, n+a[i][j], 1);
    rep(i, n) g.add_edge(sv, i, 1);
    rep(i, n) g.add_edge(n+i, tv, 1);
    
    vector<vector<int>> ans(n);
    rep(mi, m) {
        assert(g.flow(sv, tv) == n);
        rep(i, n)rep(j, m) {
            int ei = i*m+j;
            if (g.get_edge(ei).flow) {
                ans[i].push_back(a[i][j]+1);
                g.change_edge(ei, 0, 0);
            }
        }
        rep(i, n+n) g.change_edge(n*m+i, 1, 0);
    }
    
    puts("Yes");
    rep(i, n) {
        rep(j, m) cout << ans[i][j] << " \n"[j == m-1];
    }
    
    return 0;
}