A. Lucky Direction

模拟

代码实现
d = {'N' : 'S', 'S' : 'N', 'W' : 'E', 'E' : 'W'}
print(''.join(d[c] for c in input()))

B. Seek Grid

暴搜

代码实现
#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<string> s(n), t(m);
    rep(i, n) cin >> s[i];
    rep(i, m) cin >> t[i];
    
    rep(a, n-m+1)rep(b, n-m+1) {
        bool ok = true;
        rep(i, m)rep(j, m) {
            if (s[a+i][b+j] != t[i][j]) {
                ok = false;
                break;
            }
        }
        if (ok) {
            cout << a+1 << ' ' << b+1 << '\n';
            return 0;
        }
    }
    
    return 0;
}

C. Pigeonhole Query

维护每只鸽子在哪个巢里,同时维护每个巢里的鸽子数,对于超过 \(1\) 只鸽子的巢只需考察每个巢里的鸽子数的变化量

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

using namespace std;

int main() {
    int n, q;
    cin >> n >> q;
    
    vector<int> hole(n);
    rep(i, n) hole[i] = i;
    vector<int> cnt(n, 1);
    int ans = 0;
    
    auto addCnt = [&](int h, int x) {
        if (cnt[h] >= 2) ans--;
        cnt[h] += x;
        if (cnt[h] >= 2) ans++;
    };
    
    rep(qi, q) {
        int type;
        cin >> type;
        if (type == 1) {
            int p, h;
            cin >> p >> h;
            --p; --h;
            
            addCnt(hole[p], -1);
            hole[p] = h;
            addCnt(hole[p], 1);
        }
        else {
            cout << ans << '\n';
        }
    }
    
    return 0;
}

D. Gravity

经过 \(T\) 时刻后,每个方块位于 \(\max(1, Y_i-T)\) 的位置
维护每个方块所在列的下方有多少个方块,记为 \(r_i\)
\(d_j\) 表示每列满足 \(r_i = j\) 的方块的消失时间
然后模拟一下即可

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

using namespace std;

int main() {
    int n, w;
    cin >> n >> w;
    
    vector<int> x(n), y(n);
    rep(i, n) {
        cin >> x[i] >> y[i];
        x[i]--;
    }
    
    vector<int> ord(n);
    rep(i, n) ord[i] = i;
    ranges::sort(ord, [&](int i, int j) { return y[i] < y[j]; });
    
    vector<int> r(n);
    vector<int> num(w);
    for (int i : ord) {
        r[i] = num[x[i]];
        num[x[i]]++;
    }
    
    const int INF = 1001001001;
    vector<int> d(n, INF);
    {
        vector<vector<int>> blocks(n);
        rep(i, n) blocks[r[i]].push_back(i);
        rep(i, n) {
            if (blocks[i].size() != w) continue;
            int mx = 0;
            for (int j : blocks[i]) mx = max(mx, y[j]-1);
            d[i] = mx+1;
        }
    }
    
    int q;
    cin >> q;
    rep(qi, q) {
        int t, a;
        cin >> t >> a;
        --a;
        if (d[r[a]] > t) puts("Yes");
        else puts("No");
    }
    
    return 0;
}

E. Hierarchical Majority Vote

三分树
dp[v][i] 表示将点 \(v\) 的点权变为 \(i\) 时的费用(以点 \(v\) 为根的子树中的所有点的点权全部确定)
跑树形dp

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

using namespace std;

inline void chmin(int& x, int y) { if (x > y) x = y; }

int main() {
    int n;
    string s;
    cin >> n >> s;
    
    vector dp(s.size(), vector<int>(2, 1));
    rep(i, s.size()) dp[i][s[i]-'0'] = 0;
    
    const int INF = 1001001001;
    while (dp.size() > 1) {
        vector old(dp.size()/3, vector<int>(2, INF));
        swap(dp, old);
        
        for (int l = 0; l < old.size(); l += 3) {
            rep(s, 8) {
                int cost = 0;
                rep(i, 3) cost += old[l+i][s>>i&1];
                int x = __builtin_popcount(s) >= 2 ? 1 : 0;
                chmin(dp[l/3][x], cost);
            }
        }
    }
    
    int ans = max(dp[0][0], dp[0][1]);
    cout << ans << '\n';
    
    return 0;
}

F. K-th Largest Triplet

先分别对这三个序列做降序排序
然后做多路归并即可

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

using namespace std;
using ll = long long;

int main() {
    int n, K;
    cin >> n >> K;
    
    vector<ll> a(n), b(n), c(n);
    rep(i, n) cin >> a[i];
    rep(i, n) cin >> b[i];
    rep(i, n) cin >> c[i];
    
    ranges::sort(a, greater<>());
    ranges::sort(b, greater<>());
    ranges::sort(c, greater<>());
    
    priority_queue<tuple<ll, int, int, int>> q;
    auto push = [&](int i, int j, int k) {
        if (i >= n or j >= n or k >= n) return;
        ll val = a[i]*b[j] + b[j]*c[k] + c[k]*a[i];
        q.emplace(val, i, j, k);
    };
    
    push(0, 0, 0);
    rep(ki, K-1) {
        auto [val, i, j, k] = q.top(); q.pop();
        push(i+1, j, k);
        if (i == 0) push(i, j+1, k);
        if (i == 0 and j == 0) push(i, j, k+1);
    }
    
    ll ans = get<0>(q.top());
    cout << ans << '\n';
    
    return 0;
}

G. Many LCS

dp套dp的板题

回忆 \(S\)\(T\) 的LCS

dp[i][j] 表示 \(S[0:i]\)\(T[0:j]\) 的LCS

再来考虑原题:

DP[i][d] 表示使 \(T[0:i]\)\(S\) 的LCS的 dp 表为 \(d\)\(T\) 串数

具体可以参考 类似题的题解

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

using namespace std;
using mint = modint998244353;

inline void chmax(int& x, int y) { if (x < y) x = y; }

int main() {
    int n, m;
    string s;
    cin >> n >> m >> s;
    
    using vi = vector<int>;
    map<vi, mint> dp;
    dp[vi(n+1)] = 1;
    
    rep(mi, m) {
        map<vi, mint> old;
        swap(dp, old);
        
        for (auto [d, x] : old) {
            rep(c, 26) {
                vi nd = d;
                rep(i, n) if (c == s[i]-'a') {
                    chmax(nd[i+1], d[i]+1);
                }
                rep(i, n) chmax(nd[i+1], nd[i]);
                dp[nd] += x;
            }
        }
    }
    
    vector<mint> ans(n+1);
    for (auto [d, x] : dp) ans[d[n]] += x;
    rep(i, n+1) cout << ans[i].val() << ' ';
    
    return 0;
}