A. Leap Year

模拟

代码实现
import calendar
y = int(input())
if calendar.isleap(y):
    print(366)
else:
    print(365)

B. Second Best

模拟

代码实现
n = int(input())
a = list(map(int, input().split()))
print(a.index(sorted(a)[-2])+1)

C. Transportation Expenses

二分

代码实现
#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; ll m;
    cin >> n >> m;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    
    auto f = [&](int x) {
        ll s = 0;
        rep(i, n) s += min(x, a[i]);
        return s <= m;
    };
    
    const int INF = 1001001001;
    if (f(INF)) puts("infinite");
    else {
        int ac = 0, wa = INF;
        while (abs(ac-wa) > 1) {
            int wj = (ac+wa)/2;
            if (f(wj)) ac = wj; else wa = wj;
        }
        cout << ac << '\n';
    }
    
    return 0;
}

D. AtCoder Janken 3

如果你考虑“从前到后遍历能赢就赢”的贪心的话,会发现过不了样例3
考虑dp
dp[i][j] 表示到第 \(i\) 次操作为止且最后一次出的是 \(j\) 时所能获胜的最大次数

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

using namespace std;

int main() {
    int n;
    string s;
    cin >> n >> s;
    
    const int INF = 1001001001001;
    vector dp(n+1, vector<int>(3, -INF));
    rep(i, 3) dp[0][i] = 0;
    for (int i = 1; i <= n; ++i) {
        int x = 0;
        if (s[i-1] == 'R') x = 0;
        if (s[i-1] == 'P') x = 1;
        if (s[i-1] == 'S') x = 2;
        
        rep(j, 3) {
            int val = 0;
            if (j == (x+1)%3) val = 1;
            if (j == (x+2)%3) continue;
            rep(pj, 3) {
                if (j == pj) continue;
                dp[i][j] = max(dp[i][j], dp[i-1][pj]+val);
            }
        }
    }
    
    int ans = ranges::max(dp[n]);
    cout << ans << '\n';
    
    return 0;
}

E. Xor Sigma Problem

按位算贡献,具体分析见 题解

代码实现
#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];
    
    vector<int> s(n+1);
    rep(i, n) s[i+1] = s[i]^a[i];
    
    ll ans = 0;
    rep(k, 30) {
        int one = 0;
        rep(i, n+1) if (s[i]>>k&1) one++;
        ans += one*ll(n+1-one)*(1ll<<k);
    }
    rep(i, n) ans -= a[i];
    
    cout << ans << '\n';
    
    return 0;
}

F. Takahashi on Grid

假设从 \((i, y)\) 出发,走到 \(x=i+1\) 时 的最少移动次数以及对应的 \(y\) 坐标分别为 \(f_i(y)\)\(g_i(y)\),那么 \(f_i\)\(g_i\) 的复合可以在 \(O(1)\) 的时间计算得到,然后上线段树。

G. AtCoder Office

根号分治
先假设一个阈值 \(D\),再令第 \(i\) 个人对应的区间个数为 \(C_i\)
容易看出所有人的总的区间个数最多为 \(M\)
\(C_A \leqslant D\)\(C_B \leqslant D\) 时,可以直接暴力双指针做,时间复杂度为 \(O(C_A + C_B)\),参考 LC986
\(A\)\(B\) 中有一个区间的长度 \(> D\),不失一般性地,我们假设 \(A\) 的长度大于 \(D\),那么这样的 \(A\) 显然不超过 \(\lfloor\frac{M}{D}\rfloor\)
然后做一下预处理,记 f(i, j) 表示询问 \(i, j\) 的答案,其中 \(C_i > D\),暴力转移可以在 \(\mathcal{O}(\frac{M^2}{D})\) 时间内完成
根据均值不等式可知,\(\frac{M^2}{D} + QD \geqslant \sqrt{M^2Q}\),等式成立当且仅当 \(D = \frac{M}{\sqrt{Q}}\)

代码实现
#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;
    
    vector<P> records;
    vector<vector<int>> ts(n);
    rep(i, m) {
        int t, p;
        cin >> t >> p;
        --p;
        records.emplace_back(t, p);
        ts[p].push_back(t);
    }
    
    vector<bool> many(n);
    rep(i, n) many[i] = ts[i].size() > 400;
    
    vector<vector<int>> d(n);
    rep(i, n) if (many[i]) {
        d[i] = vector<int>(n);
        int s = 0, pt = 0; bool in = false;
        vector<int> sign(n, -1);
        for (auto [t, p] : records) {
            if (in) s += t-pt; 
            if (p == i) {
                in = !in;
            }
            else {
                d[i][p] += s*sign[p];
                sign[p] *= -1;
            }
            pt = t;
        }
    }
    
    int q;
    cin >> q;
    rep(qi, q) {
        int a, b;
        cin >> a>> b;
        --a; --b;
        if (many[b]) swap(a, b);
        int ans = 0;
        if (many[a]) ans = d[a][b];
        else {
            bool ain = false, bin = false;
            int ai = 0, bi = 0, pt = 0;
            while (ai < ts[a].size() and bi < ts[b].size()) {
                int ta = ts[a][ai], tb = ts[b][bi];
                int t = min(ta, tb);
                if (ain and bin) ans += t-pt;
                pt = t;
                if (ta < tb) ++ai, ain = !ain;
                else ++bi, bin = !bin;
            }
        }
        cout << ans << '\n';
    }
    
    return 0;
}