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 坐标分别为 fi(y)gi(y),那么 figi 的复合可以在 O(1) 的时间计算得到,然后上线段树。

G. AtCoder Office

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

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