T1:New Scheme

模拟

代码实现
def solve():
    s = list(map(int, input().split()))
    for i in range(8):
        if s[i]%25 != 0:
            return False
        if s[i] < 100 or s[i] > 675:
            return False
    for i in range(7):
        if s[i] > s[i+1]:
            return False
    return True
            
if solve():
    print('Yes')
else:
    print('No')

T2:Default Price

模拟

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

using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<string> c(n), d(m+1);
    vector<int> p(m+1);
    rep(i, n) cin >> c[i];
    rep(i, m) cin >> d[i+1];
    rep(i, m+1) cin >> p[i];
    
    map<string, int> mp;
    rep(i, m) mp[d[i+1]] = p[i+1];
    
    int ans = 0;
    rep(i, n) {
        int price = mp[c[i]];
        if (price == 0) price = p[0];
        ans += price;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T3:Standings

对这 \(n\) 个人按 \(\frac{a_i}{a_i+b_i}\) 的大小降序排序,但对于 \(\frac{a_i}{a_i+b_i}\) double 有精度问题,可以考虑转化成整式,即 \(a_i *(a_j+b_j) > a_j*(a_i+b_i)\)
此时发现会 wa,注意到每个人应该是按下标升序,所以应该做稳定排序

代码实现
#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), b(n);
    rep(i, n) cin >> a[i] >> b[i];
    rep(i, n) b[i] += a[i];
    
    vector<int> ans(n);
    iota(ans.begin(), ans.end(), 0);
    stable_sort(ans.begin(), ans.end(), [&](int i, int j) {
        return (ll)a[i]*b[j] > (ll)a[j]*b[i];
    });
    
    rep(i, n) cout << ans[i]+1 << ' ';
    
    return 0;
}

T4:Snuke Maze

\(\operatorname{bfs}\)

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

using namespace std;
using P = pair<int, int>;

const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};

int main() {
    int h, w;
    cin >> h >> w;
    
    vector<string> s(h);
    rep(i, h) cin >> s[i];
    
    vector<int> mp(256);
    string T = "snukes";
    rep(i, 5) mp[T[i]] = T[i+1];
    
    vector used(h, vector<bool>(w));
    queue<P> q;
    used[0][0] = true;
    q.emplace(0, 0);
    while (q.size()) {
        auto [i, j] = q.front(); q.pop();
        rep(v, 4) {
            int ni = i+di[v], nj = j+dj[v];
            if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
            if (s[ni][nj] != mp[s[i][j]]) continue;
            if (used[ni][nj]) continue;
            used[ni][nj] = true;
            q.emplace(ni, nj);
        }
    }
    
    if (used[h-1][w-1]) puts("Yes");
    else puts("No");
    
    return 0;
}
multi

T5:MEX

可以考虑枚举中间的 E,对于两边的 \(M\)\(X\),都对应着三种数 \(0, 1, 2\),于是我们不妨记 \(M_0, M_1, M_2\) 以及 \(X_0, X_1, X_2\),预处理出前缀中 M 对应的 \(M_0, M_1, M_2\) 的个数以及后缀中 X 对应的 \(X_0,X_1,X_2\) 的个数,然后利用乘法原理求出相应的贡献

代码实现
#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);
    string s;
    rep(i, n) cin >> a[i];
    cin >> s;
    
    ll ans = 0;
    vector<int> m(3), x(3);
    rep(k, n) if (s[k] == 'X') x[a[k]]++;
    auto mex = [](int a, int b, int c) {
        int s = 1<<a|1<<b|1<<c;
        int res = 0;
        while (s>>res&1) res++;
        return res;
    };
    rep(j, n) {
        if (s[j] == 'E') {
            rep(i, 3)rep(k, 3) {
                ll now = (ll)m[i]*x[k];
                ans += now*mex(i, a[j], k);
            }
        }
        if (s[j] == 'M') m[a[j]]++;
        if (s[j] == 'X') x[a[j]]--; 
    }
    
    cout << ans << '\n';
    
    return 0;
}

也可以用 \(dp\) 来做
dp[i][j][k] 表示到第 \(i\) 个数为止最后一个数对应的字符是 MEX 中的第 \(j\) 个且所选择的三个数的集合为 \(k\) 时的方案数

代码实现
#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);
    string s;
    rep(i, n) cin >> a[i];
    cin >> s;
    string T = "MEX";
    
    auto mex = [](int k) {
        int res = 0;
        while (k>>res&1) res++;
        return res;
    };
    vector dp(4, vector<ll>(8));
    dp[0][0] = 1;
    rep(i, n) {
        rep(j, 3) if (s[i] == T[j]) {
            rep(k, 8) {
                dp[j+1][k|1<<a[i]] += dp[j][k];
            }
        }
    } 
    
    ll ans = 0;
    rep(k, 8) ans += dp[3][k]*mex(k);
    cout << ans << '\n';
    
    return 0;
}

T6:Vouchers

贪心

从折扣金额较大的优惠券开始,在可以使用的范围内,对原价最低的商品用这张优惠券即可!
可以使用 std::multisetlower_bound 函数来解决。

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

int main() {
    int n, m;
    cin >> n >> m;
    
    multiset<int> s;
    ll ans = 0;
    rep(i, n) {
        int p;
        cin >> p;
        s.insert(p);
        ans += p;
    }
    
    vector<P> cp(m);
    rep(i, m) cin >> cp[i].second;
    rep(i, m) cin >> cp[i].first;
    
    sort(cp.rbegin(), cp.rend());
    
    for (auto [d, l] : cp) {
        auto it = s.lower_bound(l);
        if (it == s.end()) continue;
        s.erase(it);
        ans -= d;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T7:Minimum Xor Pair Query

如何求一个集合中的任意两数的异或的最小值?

\(\mathcal{O}(n\log n)\) 的做法:

  • 可以对原集合做升序排序,然后遍历相邻两数的异或值,同时更新最小值就能得到答案

对于原题,我们只需开两个 std::multiset 来维护即可,一个用来维护原数集,一个用来维护相邻两数的异或所构成的集合

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

using namespace std;
using uint = unsigned;
using P = pair<int, int>;

int main() {
    int q;
    cin >> q;
    
    multiset<uint> s, t;
    // 这里加哨兵的作用了为了避免判空
    s.insert(0);
    s.insert(1u<<31);
    t.insert(1u<<31);
    rep(qi, q) {
        int type;
        cin >> type;
        if (type == 3) {
            cout << *t.begin() << '\n';
        }
        else {
            uint x;
            cin >> x;
            x += 1u<<30; // 避免集合中的第一个数成为答案
            if (type == 1) {
                auto it = s.insert(x);
                uint l = *prev(it);
                uint r = *next(it);
                t.erase(t.find(l^r));
                t.insert(l^x);
                t.insert(r^x);
            }
            else {
                auto it = s.erase(s.find(x));
                int r = *it;
                uint l = *prev(it);
                t.insert(l^r);
                t.erase(t.find(l^x));
                t.erase(t.find(r^x));
            }
        }
    }
    
    return 0;
}