A. Insert

模拟

代码实现
n, k, x = map(int, input().split())
a = list(map(int, input().split()))
a.insert(k, x)
print(*a)

B. Intersection of Cuboids

模拟

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

using namespace std;

struct Point {
    int x, y, z;
};
Point input() {
    Point p;
    cin >> p.x >> p.y >> p.z;
    return p;
}

bool solve() {
    Point l1 = input();
    Point r1 = input(); 
    Point l2 = input();
    Point r2 = input();
    
    rep(i, 2) {
        if (r1.x <= l2.x) return false;
        if (r1.y <= l2.y) return false;
        if (r1.z <= l2.z) return false;
        swap(l1, l2);
        swap(r1, r2);
    }
    return true;
}

int main() {
    if (solve()) puts("Yes");
    else puts("No");
    
    return 0;
}

C. Make Them Narrow

对序列 \(A\) 做一遍升序排序,然后遍历所有大小为 \(n-k\) 的窗口即可

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

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    sort(a.begin(), a.end());
    
    int ans = 1e9;
    rep(l, k+1) {
        int r = l+(n-k)-1;
        int now = a[r] - a[l];
        ans = min(ans, now);
    }
    
    cout << ans << '\n';
    
    return 0;
}

D. Go Stone Puzzle

BFS
将当前所有格子的石头的摆放情况作为状态,然后跑最短路即可

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

using namespace std;

int main() {
    int n; 
    string s, t;
    cin >> n >> s >> t;
    s += "..";
    t += "..";
    
    map<string, int> dist;
    queue<string> q;
    dist[s] = 0; q.push(s);
    while (q.size()) {
        string s = q.front(); q.pop();
        int j = 0;
        while (s[j] != '.') ++j;
        rep(i, n+1) {
            if (s[i] == '.' or s[i+1] == '.') continue;
            string ns = s;
            swap(ns[i], ns[j]);
            swap(ns[i+1], ns[j+1]);
            if (dist.count(ns)) continue;
            dist[ns] = dist[s]+1;
            q.push(ns);
        }
    }
    
    if (dist.count(t)) cout << dist[t] << '\n';
    else cout << "-1\n";
    
    return 0;
}

E. Tree and Hamilton Path 2

考虑最后会返回到起点的情况,就是选取一点出发跑一遍dfs,树上每条边都会遍历2次,所以答案为 \(2\sum C_i\)

对于原题,我们可以考虑找到树上的一条直径,从直径上的点走到不在直径上的点再返回到直径上每条边会遍历2次,而在直径上的边只会遍历一次,所以答案就是用上面那种情况的费用减去直径的边数即可

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

using namespace std;
using ll = long long;

struct Edge {
    int to, cost;
    Edge(int to, int cost): to(to), cost(cost) {}
};

int main() {
    int n;
    cin >> n;
    
    ll ans = 0;
    vector<vector<Edge>> g(n);
    rep(i, n-1) {
        int a, b, c;
        cin >> a >> b >> c;
        --a; --b;
        g[a].emplace_back(b, c);
        g[b].emplace_back(a, c);
        ans += c*2;
    }
    
    auto dfs = [&](auto& f, int v, ll d=0, int p=-1) -> pair<ll, int> {
        auto res = make_pair(d, v);
        for (auto e : g[v]) {
            if (e.to == p) continue;
            res = max(res, f(f, e.to, d+e.cost, v));
        }
        return res;
    };
    int a = dfs(dfs, 0).second;
    ll diameter = dfs(dfs, a).first;
    ans -= diameter;
    cout << ans << '\n';
    
    return 0;
}

F. x = a^b

可以先求出满足 \(x^b \leqslant n\)\(x=a\) 的个数,只需二分即可
然后注意到 \(64 = 2^6 = 4^3 = 8^2\),可以发现 \(6\)\(3\)\(2\) 的倍数,所以可以考虑对指数 \(b\) 进行容斥

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

using namespace std;
using ll = long long;

ll calc(int b, ll n) {
    ll ac = 0, wa = n+1;
    // ac^b <= n 
    while (ac+1 < wa) {
        ll wj = (ac+wa)/2;
        auto ok = [&]{
            ll x = 1;
            rep(i, b) {
                if (n/x < wj) return false;
                x *= wj;
            }
            return x <= n;
        }();
        (ok ? ac : wa) = wj;
    }
    return ac-1;
}

int main() {
    ll n;
    cin >> n;
    
    const int M = 60;
    vector<ll> f(M);
    ll ans = 1;
    for (int b = M-1; b >= 2; --b) {
        f[b] = calc(b, n);
        for (int i = b*2; i < M; i += b) f[b] -= f[i];
        ans += f[b];
    }
    
    cout << ans << '\n';
    
    return 0;
}

G. Go Territory

可以考虑对同行连续的空格构成的连通块做缩点,然后用并查集对相邻两行中上下相邻的点做合并,再判断遍历每个点,判断当前点是否和以坐标 \((-1, -1)\) 所在行的连通块的点连通即可

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

struct Range {
    int l, r, id;
    Range(int l, int r, int id): l(l), r(r), id(id) {}
};

int main() {
    int n;
    cin >> n;
    
    const int M = 200005;
    vector<vector<int>> xs(M);
    rep(i, n) {
        int x, y;
        cin >> x >> y;
        x++; y ++;
        xs[y].push_back(x);
    }
    
    vector<vector<Range>> rngs(M);
    int m = 0;
    rep(y, M) {
        auto& nxs = xs[y];
        ranges::sort(nxs);
        int l = 0;
        for (int x : nxs) {
            if (l < x) {
                rngs[y].emplace_back(l, x, m++);
            }
            l = x+1;
        }
        rngs[y].emplace_back(l, M, m++);
    }
    
    dsu uf(m);
    rep(y, M-1) {
        auto& rngs1 = rngs[y];
        auto& rngs2 = rngs[y+1];
        vector<int> xs;
        for (auto rng : rngs1) xs.push_back(rng.l);
        for (auto rng : rngs2) xs.push_back(rng.l);
        ranges::sort(xs);
        
        int i1 = 0, i2 = 0;
        for (int x : xs) {
            while (rngs1[i1].r <= x) i1++;
            while (rngs2[i2].r <= x) i2++;
            if (rngs1[i1].l > x) continue;
            if (rngs2[i2].l > x) continue;
            uf.merge(rngs1[i1].id, rngs2[i2].id);
        }
    }
    
    ll ans = 0;
    rep(y, M) {
        for (auto rng : rngs[y]) {
            if (uf.same(0, rng.id)) continue;
            ans += rng.r - rng.l;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}