ZR-J 2025-10-29 比赛总结
分数:\(100 + 100 + 0 + 0 = 200\)
永康喵喵又没有翻车!
有了前几次翻车的教训,我形成了先写注释(对于难题)\(\rightarrow\) 仔细写题 \(\rightarrow\) 静态检查 \(\rightarrow\) 动态检查 \(\rightarrow\)(所有能做的题做完后)对拍 \(\rightarrow\) 最后核查的流程,大大降低了翻车率。如果你比较粗心,不妨也借鉴一下这套流程。
言归正传,分析题目。
T1
为什么数据这么水啊,\(n \le 50\) 是啥阴。这题明明有 \(n^2\) 做法,而且并不难,为什么不把数据范围开到 \(n \le 3000\)。
当然考场上写题速度很重要,所以我当然是暴力打 \(n^4\)。如果要 \(n^2\),可以先计算出没有老师时的握手次数,然后枚举老师的位置,更新其周围的握手情况。握手需要 \(2\) 个人进行,所以最后不要忘了 \(\div 2\)。
T2
在变换次数比较小(\(k \le 1000\))时,暴力的时间复杂度可以接受,可是如果变换次数达到 \(10^9\) 就会 T 飞。但是如果仔细分析变换的过程就会发现这是一个周期性变换。因此可以先暴力找到周期 \(a\),然后将 \(k\) 对 \(a\) 取模,再进行暴力。考虑到 \(|S| \le 1000\),如果要进一步缩短程序运行时间,甚至可以打表(我就是如此场切的)。
T3
不知道为什么 ZR 也学上了 aoao,先放两道特别水的题,然后在 T3 突然上难度,很搞人心态。
不过要是摸清了这道题的本质就不难了。今天下午我学了 Floyd 最短路算法,其本质是寻找一个中转点,然后用它更新两边点的距离。这道题也类似。我们可以设 \(f_{i, j}\) 表示当前路径的两个端点分别为 \(i, j\),且已经访问了从 \(1\) 到 \(\max(i, j)\) 的所有点时的最小时间。初始时,\(f_{1,1}=0\)。
然后进行状态转移:
-
遍历 \(i, j\)。
-
计算下一个要访问的点 \(k = \max(i, j)+1\)。如果 \(k > n\) 则跳过。
-
更新两个新状态:
-
从端点 \(j\) 扩展到 \(k\):路径变为 \((i, k)\),时间增加 \(d_{j, k}\),即 \(f_{i, k} = \min(f_{i, k}, f_{i, j} + d_{j, k})\)。
-
从端点 \(i\) 扩展到 \(k\):路径变为 \((k, j)\),时间增加 \(d_{i, k}\),即 \(f_{k, j} = \min(f_{k, j}, f_{i, j} + d_{i, k})\)。
这样扩展保证了当访问点 \(k\) 时,所有小于 \(k\) 的点都已经被访问,满足限制条件。
-
输出答案时,遍历所有 \(i\),然后取 \(f_{n, i}\) 和 \(f_{i, n}\) 的最小值作为答案。
T4
如果仔细分析,这道题就是典型的纸老虎。
不难 (其实很难) 发现,有多少个不同的横坐标,就能画多少条不同的竖线;有多少个不同的纵坐标,就能画多少条不同的横线。同时,两个人若要求得最优策略,画的线一定是横纵交替的。所以,如果 Alice 要输,那么一定由 Bob 把最后一根线画完,也就是横纵坐标数量相等。用 set 维护即可。
#include <bits/stdc++.h>
typedef long long ll;
const int N = 1e5+10;
std::set<int> xs, ys;
int n;
int main() {
std::ios::sync_with_stdio(false); std::cin.tie(0);
std::cin >> n;
for (int i = 1; i <= n; i++) {
int x, y;
std::cin >> x >> y;
xs.insert(x), ys.insert(y);
}
if (xs.size() == ys.size()) {
std::cout << "Bob\n";
} else {
std::cout << "Alice\n";
}
return 0;
}

浙公网安备 33010602011771号