PKUWC2025 D1T1 详细题解
luchenxi2012 · · Algo. & Theory
洛谷没有原题,只能写在算法理论里面……
应同学请求而作。同学找了半天没找到一篇详细的题解,希望这篇题解能够帮助到大家?
这个解法的复杂度仅为
题意
题面:有
利用部分分答题
我们发现部分分给出的是
迈出第一步:a\gt b+1
对于这个微不足道的
首先,判断出坏的电池至少得将
好了,现在我们真正踏上了解决此题的旅程!
当 a\le b+1 时呢?
是的,实际上此题只需要分讨两种情况。写的越多越容易错!
此时我们需要知道,到底怎么才能确定一些电池是好的,或是坏的呢?
我们先默认,在确定知道此次必然匹配成功之前,所有操作均为失败。我们需要利用这些失败去确定一些电池是好的或是坏的。
首先,如果我们匹配失败了一次,那么匹配的两个电池中至少一个是坏的。那么,这个东西能不能推广呢?我们能不能推出更多坏的电池呢?
显然可以。我们如果去用
所以,我们可以通过
这让我们思维打开:就算
对于上面的结论,我们可以用一个函数
我们将
使用调整法:若
故调整后次数下降,更优;故可将所有
至此,我们离正解已经不远了!
我们在筛选出一些坏电池之后,最后只会剩下一些好电池(如果还剩下坏电池,那么后面还要将它们筛选,可以直接与前面
于是我们继续分讨:
如果啥都没剩,说明压根选不出来(如果觉得不保险其实也能加,不过实测没有这样的数据。)
如果剩下一个,那么我们需要再找到一个和它配对,我们可以在之前的某个个数最小的组中挑选,参照上面的定义,也就是需要加一个
此状态下答案为
如果剩下超过一个,显然是只需要再配对一次了,所以肯定剩的越少越好,就剩两个即可。
此状态下答案为
所以,最终答案是两个取最小值,即
终于结束了……
代码
很简单,但是作者在场上为了它奋战了两个小时:
#include <bits/stdc++.h>
using namespace std;
int solve(int a, int b) { // 求左 a 右 b 时的最小匹配次数
if (!a) return 2e9; // 小心除以 0
int s = b / a, t = b % a;
return t * (s + 1) * (s + 2) / 2 +
(a - t) * s * (s + 1) / 2;
}
int main() {
int _, a, b;
scanf("%d", &_);
while (_--) {
scanf("%d%d", &a, &b);
if (a > b + 1) printf("%d\n", b + 1);
else printf("%d\n", min(solve(a - 2, b), solve(a - 1, b) + b / (a - 1)) + 1);
}
return 0;
}
制作不易,希望能对大家有所帮助!