A. Who Ate the Cake?

模拟

代码实现
a, b = map(int, input().split())
if a == b:
print(-1)
else:
print(6-a-b)

B. Piano 2

模拟

代码实现
#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<int> a(n), b(m);
rep(i, n) cin >> a[i];
rep(i, m) cin >> b[i];
vector<P> ps;
rep(i, n) ps.emplace_back(a[i], 0);
rep(i, m) ps.emplace_back(b[i], 1);
sort(ps.begin(), ps.end());
rep(i, n+m-1) {
if (ps[i].second == 0 and ps[i+1].second == 0) {
puts("Yes");
return 0;
}
}
puts("No");
return 0;
}

C. Bingo 2

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, t;
cin >> n >> t;
vector<int> row(n), col(n);
int dia1 = 0, dia2 = 0;
rep(ti, t) {
int a;
cin >> a;
--a;
int i = a/n, j = a%n;
auto add = [&](int& x) {
x++;
if (x == n) {
cout << ti+1 << '\n';
exit(0);
}
};
add(row[i]);
add(col[j]);
if (i == j) add(dia1);
if (i+j == n-1) add(dia2);
}
puts("-1");
return 0;
}

D. Intersecting Intervals

可以用总方案数容斥掉不相交的区间的个数
什么时候两区间会不相交?一个区间的右端点小于另一个区间的左端点
那么我们可以像B题那样对区间左右两端点分别标记为 01,然后放在一起排序,接着遍历所有二元组 (x,t),当 t=0 时,将答案减去前面右端点的个数,当 t=1 时,将右端点个数 +1

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
using ll = long long;
int main() {
int n;
cin >> n;
vector<P> ps;
rep(i, n) {
int l, r;
cin >> l >> r;
ps.emplace_back(l, 0);
ps.emplace_back(r, 1);
}
sort(ps.begin(), ps.end());
ll ans = (ll)n*(n-1)/2;
int rs = 0;
for (auto [x, t] : ps) {
if (t == 0) ans -= rs;
else rs++;
}
cout << ans << '\n';
return 0;
}

E. Guess the Sum

为了方便处理,不妨将 R 加上 1
Si=j=0i1aj
注意到 SRSL=(1)×SR+1×SL,同样对于 SrSl 也可以表示成 (1)×Sl+1×Sr
假设从当前点向右边连边为正贡献,向左连边为负贡献,分别用 1-1 来标记
那么 SRSL 就可以由从 L 点出发经过若干条边走到 R 点的最短路得到,关于如何求最短路,可以从当前点向左右两边进行扩展,也就是 v2i 以及 v+2i,直到扩展到 v 点在二进制下末尾第一个 1 的位置

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
using ll = long long;
int main() {
int n, l, r;
cin >> n >> l >> r;
int n2 = 1<<n;
r++;
const int INF = 1001001001;
vector<int> dist(n2+1, INF), pre(n2+1, -1);
queue<int> q;
dist[l] = 0; q.push(l);
while (q.size()) {
int v = q.front(); q.pop();
auto push = [&](int to) {
if (to < 0 or to > n2) return;
if (dist[to] != INF) return;
dist[to] = dist[v]+1;
pre[to] = v;
q.push(to);
};
rep(i, n+1) {
push(v-(1<<i));
push(v+(1<<i));
if (v>>i&1) break;
}
}
int ans = 0;
auto query = [&](int s, int t) {
int sign = 1;
if (s > t) swap(s, t), sign = -1;
{
int i = 0, j = s, w = t-s;
while (w%2 == 0) j >>= 1, i++, w >>= 1;
cout << "? " << i << ' ' << j << '\n';
}
int x;
cin >> x;
ans = (ans + x*sign + 100)%100;
};
while (r != l) {
query(pre[r], r);
r = pre[r];
}
cout << "! " << ans << '\n';
return 0;
}

F. MST Query

考虑图 G 的子图,由 G 上边权大小不超过 k 的边生成的子图 Gk(0k10)。记图 H 中的连通分量的个数为 c(H),那么图 G 上的最小生成树上的所有边的权值总和等价于 k=09(c(Gk)1)

证明:对于图 G 的最小生成树上的边,边权不超过 k 的边有 Nc(Gk)。所以,最小生成树上边权恰好为 k 的边数就是 (Nc(Gk))(Nc(Gk1))=c(Gk1)c(Gk)。于是,最小生成树上的边权和就是 k=110k(c(Gk1)c(Gk))=k=09c(Gk)10c(G10)=k=09(c(Gk)1),其中 G10 就是图 G,所以连通分量的个数为 1

代码实现
#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;
int main() {
int n, q;
cin >> n >> q;
int m = 10;
int ans = (n-1)*m;
vector<dsu> uf(m, dsu(n));
rep(qi, n-1+q) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
for (int i = c; i < m; ++i) {
if (uf[i].same(a, b)) continue;
ans--;
uf[i].merge(a, b);
}
if (qi < n-1) continue;
cout << ans << '\n';
}
return 0;
}