A. Thermometer

模拟

代码实现
#include <bits/stdc++.h>

using namespace std;

int main() {
    double x;
    cin >> x;
    
    if (x >= 38) puts("1");
    else if (x >= 37.5) puts("2");
    else puts("3");
    
    return 0;
}

B. Ticket Gate Log

模拟

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

using namespace std;

int main() {
    string s;
    cin >> s;
    
    int ans = 0;
    char expect = 'i';
    for (char c : s) {
        if (c != expect) ans++;
        expect = c^'o'^'i';
    }
    if (s.back() == 'i') ans++;
    
    cout << ans << '\n';
    
    return 0;
}

C. Variety Split Easy

前后缀分解

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

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<int> numl(n+1), numr(n+1);
    {
        unordered_set<int> st;
        rep(i, n) {
            st.insert(a[i]);
            numl[i+1] = st.size();
        }
    }
    {
        unordered_set<int> st;
        for (int i = n-1; i >= 0; --i) {
            st.insert(a[i]);
            numr[i] = st.size();
        }
    }
    
    int ans = 0;
    for (int i = 1; i < n; ++i) {
        ans = max(ans, numl[i]+numr[i]);
    }
    
    cout << ans << '\n';
    
    return 0;
}

D. Cubes

\(N = x^3 - y^3 = (x-y)(x^2+ xy + y^2)\)
\(d = x-y\)
我们可以枚举这个 \(d\)
\(x = y+d\)
\(x^3 - y^3 = d^3 + 3yd(y+d)\)
\(d^3 < N\)
\(y(y+d) = \frac{N-d^3}{3d}\)
其中 \(\frac{N-d^3}{3d}\) 是个常数,不妨记为 \(C\)
\(y^2 + dy - C = 0\)
然后用求根公式解出 \(y\)

代码实现
#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;
    cin >> n;
    
    for (ll d = 1; d*d*d < n; ++d) {
        ll c = n-d*d*d;
        if (c%(3*d)) continue;
        c /= 3*d;
        ll y = (sqrt(d*d+4*c)-d)/2;
        if (y*y+d*y-c == 0) {
            cout << y+d << ' ' << y << '\n';
            return 0;
        }
    }
    
    cout << "-1\n";
    
    return 0;
}

E. Path Decomposition of a Tree

任选一个点作为根,并考虑包含叶子的路径会发生什么,就会发现最终只能依次割掉大小为 \(K\) 的子树。可以用 \(\operatorname{dfs}\) 来实现

代码实现
#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;
    int nk = n*k;
    
    vector<vector<int>> to(nk);
    rep(i, nk-1) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        to[a].push_back(b);
        to[b].push_back(a);
    }
    
    bool ok = true;
    auto dfs = [&](auto& f, int v, int p=-1) -> int {
        int res = 1;
        int deg = 0;
        for (int u : to[v]) {
            if (u == p) continue;
            int sz = f(f, u, v);
            if (sz%k) deg++;
            res += sz;
        }
        if (res%k) deg++;
        if (deg > 2) ok = false;
        return res;
    };
    dfs(dfs, 0);
    
    if (ok) puts("Yes");
    else puts("No");
    
    return 0;
}

F. Variety Split Hard

dp[j][i] 表示将前 \(i\) 个数分成 \(j\) 段时的最大值

\( dp[j+1][i] = \max\limits_{p < i} (dp[j][p] + f(p, i)) \)

其中 \(f(p, i)\) 表示 \((A_{p+1},A_{p+2}, \cdots, A_i)\) 的种类数
然后用线段树来加速即可

同时这种做法和加强版 CF833B 一样

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

using namespace std;

int op(int x, int y) { return max(x, y); }
int e() { return 0; }

int mapping(int f, int x) { return x+f; }
int composition(int f, int g) { return f+g; }
int id() { return 0; }

int main() {
    int n;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<int> pre(n);
    {
        vector<int> pos(n+1, -1);
        rep(i, n) {
            pre[i] = pos[a[i]];
            pos[a[i]] = i;
        }
    }
    
    using seg = lazy_segtree<int, op, e, int, mapping, composition, id>;
    vector<seg> t(3, seg(n));
    rep(i, n) {
        rep(j, 2) {
            int now = t[j].all_prod();
            t[j+1].set(i, now);
        }
        rep(j, 3) {
            t[j].apply(pre[i]+1, i+1, 1);
        }
    }
    
    int ans = t[2].all_prod();
    cout << ans << '\n';
    
    return 0;
}

G. Maximize Distance

首先,考虑“是否可以将最短距离增加到 1 以上?”时,问题就变成了“删除若干条边,使得无法从点 \(1\) 到达点 \(N\)”,因此是最小割问题!如果用同样的思路来思考原问题,就会发现它也是一个"\(k\) 值燃烧填充"问题,可以通过最小割来解决!