T1:Yay!

模拟

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

using namespace std;

int main() {
    string s;
    cin >> s;
    
    vector<int> cnt(256);
    for (char c : s) cnt[c]++;
    
    char one = '?';
    for (char c = 'a'; c <= 'z'; ++c) {
        if (cnt[c] == 1) one = c;
    }
    
    rep(i, s.size()) {
        if (s[i] == one) {
            cout << i+1 << '\n';
        }
    }
    
	return 0;
}

T2:Which is ahead?

模拟

代码实现
#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> p(n);
    rep(i, n) cin >> p[i];
    
    vector<int> x(n+1);
    rep(i, n) x[p[i]] = i;
    
    int q;
    cin >> q;
    rep(qi, q) {
        int a, b;
        cin >> a >> b;
        if (x[a] < x[b]) cout << a << '\n';
        else cout << b << '\n';
    }
    
	return 0;
}

T3:Many Replacement

只需记录每种字符最后变成了哪个字符即可

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

using namespace std;

int main() {
    int n, q;
    string s;
    cin >> n >> s >> q;
    
    string t;
    rep(i, 26) t += 'a'+i;
    
    rep(qi, q) {
        char c, d;
        cin >> c >> d;
        rep(i, 26) {
            if (t[i] == c) t[i] = d;
        }
    }
    
    rep(i, n) {
        int j = s[i]-'a';
        s[i] = t[j];
    }
    
    cout << s << '\n';
    
	return 0;
}

T4:Square Pair

可以先将每个数中的最大的平方因子除掉,然后就变成简单的组合计数问题了

代码实现
#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;
    cin >> n;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    rep(i, n) {
        int x = a[i];
        for (int j = 2; ; ++j) {
            int y = j*j;
            if (y > x) break;
            while (x%y == 0) x /= y; 
        }
        a[i] = x;
    }
    
    ll ans = 0;
    int zero = 0;
    rep(i, n) {
        if (a[i] == 0) {
            zero++;
        }
    }
    ans += (ll)zero*(zero-1)/2;
    map<int, int> mp;
    for (int x : a) {
        if (x == 0) continue;
        ans += zero;
        ans += mp[x];
        mp[x]++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T5:Last Train

建反图跑Dijkstra
用大根堆来做堆优化

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

struct Edge {
    int from; ll l, d, k, c;
    Edge(int from=-1, ll l=0, ll d=0, ll k=0, ll c=0): from(from), l(l), d(d), k(k), c(c) {}
};

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<Edge>> g(n);
    rep(i, m) {
        int l, d, k, c, a, b;
        cin >> l >> d >> k >> c >> a >> b;
        --a; --b;
        g[b].emplace_back(a, l, d, k, c);
    }
    
    const ll INF = 2e18;
    vector<ll> f(n, -INF);
    f[n-1] = INF;
    priority_queue<P> q;
    q.emplace(INF, n-1);
    while (q.size()) {
        auto [t, v] = q.top(); q.pop();
        if (f[v] != t) continue;
        for (auto&& e : g[v]) {
            ll nt = t-e.c;
            if (e.l > nt) continue;
            ll k = (nt-e.l)/e.d;
            k = min(k, e.k-1);
            ll nf = e.l+e.d*k;
            if (f[e.from] >= nf) continue;
            f[e.from] = nf;
            q.emplace(nf, e.from);
        }
    }
    
    rep(i, n-1) {
        ll ans = f[i];
        if (ans == -INF) puts("Unreachable");
        else cout << ans << '\n';
    }
    
    return 0;
}

T6:Black Jack

注意到庄家的决策是固定的,所以我们可以把 \(y\) 在不同值的分布概率求出来
f[i] 表示 \(y = i\) 的概率

你只有在 \(x \leqslant N\) 且 (\(y > N\)\(x > y\)) 的情况下能获胜

\(x \leqslant N\) 这个条件可以不考虑
对于 \(y>N\),它的概率就是 \(\sum\limits_{i = {N+1}}^{L+D-1} f[i]\)

而对于 \(x > y\),不妨令 \(g[i]\) 表示从 \(x = i\) 时掷骰子最后的胜率,从后往前转移
最后的答案就是 \(g[0]\)

可以用前缀和来优化

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

using namespace std;

int main() {
    int n, l, d;
    cin >> n >> l >> d;
    
    int m = max(n, l+d)+5;
    vector<double> dy(m);
    {
        vector<double> dp(m);
        dp[0] = 1;
        double s = 0;
        for (int i = 1; i < m; ++i) {
            s += dp[i-1];
            if (i-d-1 >= 0) s -= dp[i-d-1];
            // double now = 0;
            // for (int j = 1; j <= d; ++j) {
            //     if (i-j >= 0) now += dp[i-j];
            // }
            // now /= d;
            double now = s/d;
            if (i < l) dp[i] = now;
            else dy[i] = now;
        }
    }
    
    n++;
    vector<double> win(n);
    {
        double now = 0;
        for (int i = n; i < m; ++i) now += dy[i];
        rep(i, n) {
            win[i] = now;
            now += dy[i];
        }
    }
    
    double ans = 0;
    {
        vector<double> dp(n+d+1);
        double s = 0;
        for (int i = n-1; i >= 0; --i) {
            s += dp[i+1];
            s -= dp[i+d+1];
            // double now = 0;
            // for (int j = 1; j <= d; ++j) now += dp[i+j];
            // now /= d;
            double now = s/d;
            dp[i] = max(win[i], now);
        }
        ans = dp[0];
    }
    
    printf("%.10f\n", ans);
    
    return 0;
}

T7:Retroactive Range Chmax

设置节点的数据结构:

  • 添加/删除值
  • 询问 max

所以可以用 multiset 来实现

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

using namespace std;

struct segtree {
    int n;
    vector<multiset<int>> d;
    segtree(int mx=0) {
        n = 1;
        while (n < mx) n <<= 1;
        d.resize(n*2);
    }
    void add(int l, int r, int x) {
        l += n; r += n;
        while (l < r) {
            if (l%2) d[l].insert(x), l++;
            if (r%2) r--, d[r].insert(x);
            l >>= 1; r >>= 1;
        }
    }
    void del(int l, int r, int x) {
        l += n; r += n;
        while (l < r) {
            if (l%2) d[l].erase(d[l].find(x)), l++;
            if (r%2) r--, d[r].erase(d[r].find(x));
            l >>= 1; r >>= 1;
        }
    }
    int get(int i) {
        int res = 0;
        i += n;
        while (i) {
            if (d[i].size()) res = max(res, *d[i].rbegin());
            i >>= 1;
        }
        return res;
    }
};

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    
    int n;
    cin >> n;
    
    segtree t(n);
    rep(i, n) {
        int a;
        cin >> a;
        t.add(i, i+1, a);
    }
    
    int q;
    cin >> q;
    vector<tuple<int, int, int>> qs(q);
    rep(qi, q) {
        int type; 
        cin >> type;
        if (type == 1) {
            int l, r, x;
            cin >> l >> r >> x;
            --l;
            t.add(l, r, x);
            qs[qi] = tie(l, r, x);
        }
        if (type == 2) {
            int i;
            cin >> i;
            --i;
            auto [l, r, x] = qs[i];
            t.del(l, r, x);
        }
        if (type == 3) {
            int i;
            cin >> i;
            --i;
            int ans = t.get(i);
            cout << ans << '\n';
        }
    }
    
    return 0;
}