A. Poisonous Oyster

简单分讨

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

using namespace std;

int main() {
    string s1, s2;
    cin >> s1 >> s2;
    
    int ans = 1;
    if (s1 == "fine") ans += 2; 
    if (s2 == "fine") ans += 1;
    
    cout << ans << '\n';
    
    return 0;
}

B. A..B..C

模拟

代码实现
#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 n = s.size();
    
    int ans = 0;
    rep(i, n)rep(j, n)rep(k, n) {
        if (i >= j or j >= k) continue;
        if (j-i != k-j) continue;
        if (s[i] != 'A') continue;
        if (s[j] != 'B') continue;
        if (s[k] != 'C') continue;
        ans++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

C. Make it Simple

仅考虑 \(a<b\) 的边,可以用 std::set 来维护

代码实现
#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, m;
    cin >> n >> m;
    
    set<P> edges;
    rep(i, m) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        if (a == b) continue;
        if (a > b) swap(a, b);
        if (edges.count(P(a, b))) continue;
        edges.emplace(a, b);
    }
    
    int ans = m-edges.size();
    cout << ans << '\n';
    
    return 0;
}

D. Swap to Gather

考虑每个 1 左边 0 的个数构成的序列,不妨记为 \(a\)
问题就变成了可以对 \(a\) 通过 +1-1 使得 \(a\) 序列每个数相等的最小操作次数
结论是当目标值取到 \(a\) 的中位数时操作次数最少

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

using namespace std;
using ll = long long;

int main() {
    int n;
    string s;
    cin >> n >> s;
    
    vector<int> p;
    rep(i, n) if (s[i] == '1') p.push_back(i);
    int k = p.size();
    rep(i, k) p[i] -= i;
    
    int med = p[k/2];
    ll ans = 0;
    rep(i, k) ans += abs(med-p[i]);
    cout << ans << '\n';
    
    return 0;
}

E. GCD of Subset

调和级数
统计每种数的倍数的个数

代码实现
#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];
    
    const int m = 1000000;
    vector<int> num(m+1);
    for (int na : a) num[na]++;
    vector<int> c(m+1);
    for (int j = 1; j <= m; ++j) {
        for (int i = j; i <= m; i += j) c[j] += num[i];
    }
    
    vector<int> best(m+1);
    for (int g = 1; g <= m; ++g) {
        if (c[g] < k) continue;
        for (int i = g; i <= m; i += g) best[i] = g;
    }
    
    rep(i, n) {
        int ans = best[a[i]];
        cout << ans << '\n';
    }
    
    return 0;
}

F. Prefix LIS Query

离线(当然也可以在线)
将每个询问按 \(R\) 值做升序排序
然后遍历每个 \(R\),求出到当前为止的 \(\operatorname{lis}\)
dp[i] 表示长度为 \(i\)\(\operatorname{lis}\) 的最后一个数的最小值
这个序列可以用二分来求
对于 \(R\) 对应的每个询问的答案,可以对上面的 \(dp\) 序列二分

代码实现
#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, q;
    cin >> n >> q;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    vector<vector<P>> qs(n);
    rep(i, q) {
        int r, x;
        cin >> r >> x;
        --r;
        qs[r].emplace_back(i, x);
    }
    
    const int INF = 1001001001;
    vector<int> dp(n, INF);
    vector<int> ans(q);
    rep(i, n) {
        int j = lower_bound(dp.begin(), dp.end(), a[i]) - dp.begin();
        dp[j] = a[i];
        for (auto [qi, x] : qs[i]) {
            ans[qi] = lower_bound(dp.begin(), dp.end(), x+1) - dp.begin();
        }
    }
    
    rep(i, q) cout << ans[i] << '\n';
    
    return 0;
}