C - Min Difference

枚举每个元素\(a_i\),通过\(lower\_bound\)找到\(b\)中第一个大于等于\(a_i\)的元素的下标\(j\),然后取\(min(|a_i-b_j|,|a_i-b_{j-1}|)\)

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int a[MAXN], b[MAXN] = {INF};
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= m; ++i) cin >> b[i];
    sort(b + 1, b + m + 1);
    int res = INF;
    for (int i = 1; i <= n; ++i) {
        int j = lower_bound(b + 1, b + m + 1, a[i]) - b;
        res = min({res, abs(b[j] - a[i]), abs(a[i] - b[j - 1])});
    }
    cout << res << '\n';
    system("pause");
    return 0;
}
D - Querying Multiset

本题没有区间查询的操作,所以可以不用线段树等数据结构来实现,我们考虑用优先队列的方法,维护一个\(add\)标记,表示队列中的数增加的值。

#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    priority_queue<int, vector<int>, greater<int>> Q;
    int q;
    cin >> q;
    int add = 0;
    while (q--) {
        int opt, x;
        cin >> opt;
        switch (opt) {
            case 1: 
                cin >> x;
                Q.push(x - add); // 因为队列中的数默认是+add的, 所以新入队的元素要-add
                                 // 如果不减add, 考虑一个元素刚入队就出队的情况, 那它就变成了x+add
                break;
            case 2:
                cin >> x;
                add += x;
                break;
            default:
                cout << Q.top() + add << '\n';
                Q.pop();
                break;
        }
    }
    system("pause");
    return 0;
}
E - Safety Journey

因为题目给定的是完全图并且不能走的边至多有\(5000\),所以我们可以反向思考,只存无法到达的边。

考虑动态规划的解法:

\(dp[i][j]\)表示第\(i\)天在\(j\)点的方案数。

\(dp[i][j] = sum - \sum_{v}^{n} dp[i-1][v](sum表示上一天所有的方案数的和,v表示无法从j到达的点)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 5e3 + 5;
const int MOD = 998244353;
int dp[MAXN][MAXN];
vector<int> e[MAXN];
signed main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= n; ++i) {
        e[i].push_back(i);
    }
    while (m--) {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dp[0][1] = 1;
    int prev = 1; // 上一天所有方案数的和
    for (int i = 1; i <= k; ++i) {
        int cur = 0;
        for (int u = 1; u <= n; ++u) {
            dp[i][u] = prev;
            for (int v: e[u]) {
                dp[i][u] = (dp[i][u] - dp[i - 1][v] + MOD) % MOD;
            }
            cur = (cur + dp[i][u]) % MOD;
        }
        prev = cur;
    }
    cout << dp[k][1] << '\n';
    system("pause");
    return 0;
}