C. ~

注意到条件 \(2\),可知峰点在左谷点在右
也就是统计相邻两数之间满足 <<..<>..>><.. 这样的子段个数
考虑如何计算答案:固定中间所有的 >,然后两边的 < 任选,根据乘法原理,将两边的 < 的个数乘起来就是对答案的贡献
这里做一下字符串压缩再统计会比较方便

代码实现
#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>;

int main() {
    int n;
    cin >> n;
    
    vector<int> p(n);
    rep(i, n) cin >> p[i];
    
    vector<int> d;
    rep(i, n-1) d.push_back((p[i] < p[i+1]) ? 0 : 1);
    
    vector<P> rle;
    for (int x : d) {
        if (rle.size() and rle.back().first == x) rle.back().second++;
        else rle.emplace_back(x, 1);
    }
    
    ll ans = 0;
    rep(i, rle.size()) {
        if (rle[i].first == 1) {
            ll l = 0, r = 0;
            if (0 < i) l = rle[i-1].second;
            if (i+1 < rle.size()) r = rle[i+1].second;
            ans += l*r;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}

D. Garbage Removal

开两个 vector<set<int>> 乱搞

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

using namespace std;

int main() {
    int h, w, n;
    cin >> h >> w >> n;
    
    vector<set<int>> row(h), col(w);
    rep(i, n) {
        int x, y;
        cin >> x >> y;
        --x; --y;
        row[x].insert(y);
        col[y].insert(x);
    }
    
    int q;
    cin >> q;
    rep(qi, q) {
        int type, i;
        cin >> type >> i;
        --i;
        int ans = 0;
        if (type == 1) {
            ans = row[i].size();
            for (int j : row[i]) col[j].erase(i);
            row[i] = set<int>();
        }
        else {
            ans = col[i].size();
            for (int j : col[i]) row[j].erase(i);
            col[i] = set<int>();
        }
        cout << ans << '\n';
    }
    
    return 0;
}

E. Popcount Sum 3

数位dp
dp[i][j][s][p] 表示已经确定了高 \(i\) 位,所有位是否和 \(n\) 匹配(匹配:\(s=0\), 不匹配:\(s=1\)),前面是否已经有高位被设置为 \(1\)(是: \(j=1\),否:\(j=0\)),\(\operatorname{popcount}\) 是否为 \(p\)

代码实现
#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 ll = long long;
using mint = modint998244353;

const int M = 60;
mint dp[61][2][2][61];

void solve() {
    ll n; int k;
    cin >> n >> k;
    n++;
    
    rep(i, M+1)rep(j, 2)rep(s, 2)rep(p, k+1) dp[i][j][s][p] = 0;
    dp[M][0][0][0] = 1;
    for (int i = M-1; i >= 0; --i) {
        rep(j, 2)rep(s, 2)rep(p, k+1) {
            mint now = dp[i+1][j][s][p];
            if (now == 0) continue;
            rep(a, 2) {
                int ns = s, np = p+a;
                if (s == 0) {
                    if (a < (n>>i&1)) ns = 1;
                    if (a > (n>>i&1)) continue;
                }
                if (np > k) continue;
                dp[i][j][ns][np] += now;
                if (j == 0 and a) dp[i][1][ns][np] += now*(1ll<<i); 
            }
        }
    }
    
    mint ans = dp[0][1][1][k];
    cout << ans.val() << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

F. Compare Tree Weights

dfs序+树状数组

代码实现
#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 P = pair<int, int>;

int main() {
    int n;
    cin >> n;
    
    vector<vector<int>> to(n);
    vector<P> es;
    rep(i, n-1) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        es.emplace_back(a, b);
        to[a].push_back(b);
        to[b].push_back(a);
    }
    
    vector<int> in(n), out(n); int vid = 0;
    auto dfs = [&](auto& f, int v, int p=-1) -> void {
        in[v] = vid++;
        for (int u : to[v]) {
            if (u == p) continue;
            f(f, u, v);
        }
        out[v] = vid;
    };
    dfs(dfs, 0);
    
    fenwick_tree<int> t(n);
    rep(i, n) t.add(i, 1);
    
    int q;
    cin >> q;
    rep(qi, q) {
        int type;
        cin >> type;
        if (type == 1) {
            int v, w;
            cin >> v >> w;
            --v;
            t.add(in[v], w);
        }
        else {
            int ei;
            cin >> ei;
            --ei;
            auto [a, b] = es[ei];
            if (in[a] < in[b]) swap(a, b);
            int as = t.sum(in[a], out[a]);
            int bs = t.sum(0, n) - as;
            cout << abs(as-bs) << '\n';
        }
    }
    
    return 0;
}

G. Travelling Salesman Problem

dp[i][x] 表示拿到物品 \(i\) 且位于坐标 \(x\) 的最小代价
然后用 \(\operatorname{slope trick}\) 优化一下即可