G题暴力有点难绷。。

T1:Past ABCs

考虑后三个字符构成的十进制数即可

注意ABC000也要考虑

代码实现
s = input()
id = int(s[3:])
if 1 <= id <= 349 and id != 316:
    print('Yes')
else:
    print('No')

T2:Dentist Aoki

模拟

代码实现
#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<bool> hole(n+1);
    for (int i = 1; i <= n; ++i) hole[i] = true;
    
    rep(qi, q) {
        int t;
        cin >> t;
        hole[t] = !hole[t];
    }
    
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        if (hole[i]) ans++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T3:Sort

对于 \(i = 1, 2, \cdots n\),通过不断地将 \(a[i]\)\(a[a[i]]\) 交换使得 \(a[i]\) 最终位于正确的位置上

代码实现
#include <bits/stdc++.h>
#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<int> a(n+1);
    rep(i, n) cin >> a[i+1];
    
    vector<P> ans;
    for (int i = 1; i <= n; ++i) {
        while (a[i] != i) {
            int j = a[i];
            swap(a[i], a[j]);
            ans.emplace_back(i, j);
        }
    }
    
    cout << ans.size() << '\n';
    for (auto [i, j] : ans) cout << i << ' ' << j << '\n';
    
    return 0;
}

T4:New Friends

对于一个连通块的贡献就是从这个连通块中任选两点连边的方案数容斥掉已经存在于这个连通块中的边数

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

ll c2(ll n) { return n*(n-1)/2; }

int main() {
    int n, m;
    cin >> n >> m;
    
    dsu uf(n);
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        uf.merge(a, b);
    }
    
    ll ans = 0;
    rep(i, n) if (uf.leader(i) == i) {
        int s = uf.size(i);
        ans += c2(s);
    }
    ans -= m;
    
    cout << ans << '\n';
    
    return 0;
}

T5:Toward 0

f(u) 表示从 \(u\) 开始变成 \(0\) 的最小期望值

\( f(u) = \min\{f(\lfloor\frac{u}{A}\rfloor) + X, \sum\limits_{b=2}^6 (\frac{1}{5} f(\lfloor\frac{u}{b}\rfloor)) + \frac{6}{5}Y\} \)

其中 \(\frac{6}{5}Y\) 表示掷到 \(1\) 时的期望,可以考虑 \(E = Y + \frac{1}{6}E\)

然后用记忆化搜索即可

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

using namespace std;
using ll = long long;

int main() {
    ll n; int a, x, y;
    cin >> n >> a >> x >> y;
    
    map<ll, double> memo;
    auto f = [&](auto& f, ll n) -> double {
        if (n == 0) return 0;
        if (memo.count(n)) return memo[n];
        double res = f(f, n/a) + x;
        double dice = 0;
        for (int b = 2; b <= 6; ++b) {
            dice += f(f, n/b);
        }
        dice /= 5;
        dice += y*6./5;
        res = min(res, dice);
        return memo[n] = res;
    };
    
    double ans = f(f, n);
    printf("%.10f\n", ans);
    
    return 0;
}

T6:Transpose

建出表达式树后在上面dfs即可

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

using namespace std;

struct Parser {
    string s;
    int si;
    struct Node {
        vector<int> to;
        char c;
        Node(char c=0): c(c) {}
    };
    vector<Node> nodes;
    int root;
    void parse() {
        si = 0;
        root = expr();
    }
    int charNode() {
        int v = nodes.size();
        nodes.push_back(Node(s[si++]));
        return v;
    }
    int expr() {
        int v = nodes.size();
        nodes.push_back(Node());
        while (si < s.size()) {
            if (s[si] == ')') break;
            if (s[si] == '(') {
                si++;
                int u = expr();
                nodes[v].to.push_back(u);
                si++;
            }
            else {
                int u = charNode();
                nodes[v].to.push_back(u);
            }
        }
        return v;
    }
    
    void dfs(int v, bool flip) {
        Node& node = nodes[v];
        if (node.c) {
            char c = node.c;
            if (!flip) {
                if (islower(c)) c = toupper(c);
                else c = tolower(c);
            }
            cout << c;
        }
        else {
            if (flip) reverse(node.to.begin(), node.to.end());
            for (int u : node.to) dfs(u, !flip);
        }
    } 
    void output() {
        dfs(root, false);
        cout << '\n';
    }
};

int main() {
    Parser p;
    cin >> p.s;
    
    p.parse();
    p.output();
    
    return 0;
}

T7:Mediator

根据题意可知本题强制在线

可以考虑启发式合并,时间复杂度是 \(\mathcal{O}(n\log n)\)

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

using namespace std;
using ll = long long;

const int mod = 998244353;

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    
    int n, q;
    cin >> n >> q;
    
    vector<int> par(n, -1);
    vector<vector<int>> to(n);
    vector<int> root(n), sz(n, 1);
    rep(i, n) root[i] = i;
    
    int x = 0;
    rep(qi, q) {
        ll A, B, C;
        cin >> A >> B >> C;
        int type = ((A*(x+1))%mod)%2 + 1;
        int a = ((B*(x+1))%mod)%n;
        int b = ((C*(x+1))%mod)%n;
        
        if (type == 1) {
            if (sz[root[a]] < sz[root[b]]) swap(a, b);
            sz[root[a]] += sz[root[b]];
            auto dfs = [&](auto& f, int v, int p=-1) -> void {
                par[v] = p;
                root[v] = root[a];
                for (int u : to[v]) {
                    if (u == p) continue;
                    f(f, u, v);
                }
            };
            dfs(dfs, b);
            par[b] = a;
            to[a].push_back(b);
            to[b].push_back(a);
        }
        else {
            int ans = -1;
            int pa = par[a], pb = par[b];
            if (pa == pb and pa != -1) ans = pa;
            else if (pa != -1 and par[pa] == b) {
                ans = pa;
            }
            else if (pb != -1 and par[pb] == a) {
                ans = pb;
            }
            ans++;
            cout << ans << '\n';
            x = ans;
        }
    }
    
    return 0;
}