A. Cut

模拟

代码实现
#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];
rotate(a.begin(), a.begin()+(n-k), a.end());
rep(i, n) cout << a[i] << ' ';
return 0;
}

B. Decrease 2 max elements

模拟

代码实现
#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> a(n);
rep(i, n) cin >> a[i];
int ans = 0;
while (1) {
ranges::sort(a, greater<>());
if (a[1] <= 0) break;
a[0]--; a[1]--;
ans++;
}
cout << ans << '\n';
return 0;
}

C. Triple Attack

周期性

把 {1, 1, 3} 看成是一个组合技,用这 3 次攻击可以让敌人掉 5 点血
对每个敌人先尽可能地用组合技,如果还有剩余血量,就暴力模拟即可

代码实现
#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> h(n);
rep(i, n) cin >> h[i];
ll t = 0;
rep(i, n) {
int x = h[i]/5;
t += x*3;
h[i] -= x*5;
while (h[i] > 0) {
t++;
if (t%3 == 0) h[i] -= 3;
else h[i]--;
}
}
cout << t << '\n';
return 0;
}

D. Minimum Steiner Tree

显然应该从叶子节点开始删,可以考虑以某个关键点跑dfs
一个点被保留当且仅当以它为根的子树中包含关键点

代码实现
#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<vector<int>> to(n);
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
vector<int> vs(k);
rep(i, k) cin >> vs[i], vs[i]--;
vector<bool> selected(n);
rep(i, k) selected[vs[i]] = true;
vector<int> num(n);
auto dfs = [&](auto& f, int v, int p=-1) -> void {
if (selected[v]) num[v]++;
for (int u : to[v]) {
if (u == p) continue;
f(f, u, v);
num[v] += num[u];
}
};
dfs(dfs, vs[0]);
int ans = 0;
rep(i, n) if (num[i] > 0) ans++;
cout << ans << '\n';
return 0;
}

E. Train Delay

注意到,Ti+XiSj+XjTi+XiSjXj
于是,可以得到 Xj=max(Ti+Xi)Sj
可以按 Sj 递增的顺序来求出所有的 Xi,暴力模拟的时间复杂度为 O(M2)

下面考虑优化:
对每个站点维护一个二元组序列 {(Ti,Ti+Xi)} 的信息
对于 max(Ti+Xi),可以开一个数组 maxT 来维护,maxT[a] 就表示到站时间在当前火车的发车时间之前且目的地在站点 a 处的 max(Ti+Xi)
可以考虑用小根堆来维护每个站点的二元组序列,这样就能保证 Ti 单调递增了

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
using PQ = priority_queue<P, vector<P>, greater<P>>;
struct Train {
int a, b, s, t, i;
Train(int a, int b, int s, int t, int i): a(a), b(b), s(s), t(t), i(i) {}
bool operator<(const Train& o) const {
return s < o.s;
}
};
int main() {
int n, m, x1;
cin >> n >> m >> x1;
vector<Train> trains;
rep(i, m) {
int a, b, s, t;
cin >> a >> b >> s >> t;
--a; --b;
trains.emplace_back(a, b, s, t, i);
}
sort(trains.begin(), trains.end());
vector<int> x(m);
vector<int> maxT(n);
vector<PQ> q(n);
for (auto [a, b, s, t, i] : trains) {
if (i == 0) x[i] = x1;
else {
while (q[a].size()) {
auto [nt, val] = q[a].top();
if (nt > s) break;
q[a].pop();
maxT[a] = max(maxT[a], val);
}
x[i] = max(0, maxT[a]-s);
}
q[b].emplace(t, t+x[i]);
}
rep(i, m) if (i) cout << x[i] << ' ';
return 0;
}

F. Dividing Game

对每个数求一遍 sg 函数,打表可以发现 sg(x) 就是 x 的可重复质因子集合的大小,然后直接套 sg 定理即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
const int M = 100005;
vector<int> g(M);
for (int i = 1; i < M; ++i) {
int now = 0;
int x = i;
for (int d = 2; d*d <= x; ++d) {
if (x%d != 0) continue;
while (x%d == 0) now++, x /= d;
}
if (x != 1) now++;
g[i] = now;
}
int n;
cin >> n;
int x = 0;
rep(i, n) {
int a; cin >> a;
x ^= g[a];
}
if (x == 0) puts("Bruno");
else puts("Anna");
return 0;
}

G. Add and Multiply Queries

黑体字是突破口,注意到询问3的答案不超过 1e18 就很简单了
如果区间 [l,r] 中的 Bi0 的个数超过 60 个,那么执行乘法运算的话显然会超过 1e18,所以我们可以大胆断定区间中 Bi0 的位置不超过 60
对于 Bi=1 的连续区间只需执行加法即可

考虑维护满足以下需求的数据结构:

  • 求出下一个满足 Bi2 的位置 i std::set
  • 区间中 A 的累加和 树状数组
代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
cin.tie(nullptr) -> sync_with_stdio(false);
int n;
cin >> n;
vector<int> a(n), b(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
fenwick_tree<ll> d(n);
rep(i, n) d.add(i, a[i]);
set<int> st;
rep(i, n) if (b[i] > 1) st.insert(i);
st.insert(n);
int q;
cin >> q;
rep(qi, q) {
int type;
cin >> type;
if (type == 3) {
int l, r;
cin >> l >> r;
--l;
ll v = 0;
while (l < r) {
int i = *st.lower_bound(l);
i = min(i, r);
v += d.sum(l, i);
if (i == r) break;
v = max(v+a[i], v*b[i]);
l = i+1;
}
cout << v << '\n';
}
else {
int i, x;
cin >> i >> x;
--i;
if (type == 1) {
d.add(i, x-a[i]);
a[i] = x;
}
else {
b[i] = x;
if (b[i] > 1) st.insert(i); else st.erase(i);
}
}
}
return 0;
}