1 条题解
-
0
题目理解
有 个容器,第 个容器初始有 单位水。
总和 能被 整除。
操作:选择 ,从容器 向容器 倒入任意数量的水(可以倒 0 单位)。
问能否通过若干次操作,使所有容器水量相等。
核心观察
-
最终水量
由于总水量不变,最终每个容器水量应为 -
操作方向限制
水只能从左向右倒()。
这意味着:- 左边的水可以补给右边
- 右边的水永远无法倒回左边
-
从左到右贪心策略
从左到右扫描():- 如果当前容器 的水量 ,则它无法从右边得到水,直接失败
- 如果 ,则多出的水必须全部倒给右边(因为不能倒回左边,也不能倒给更左边的容器)
- 倒水后, 变成 , 增加
-
正确性说明
由于只能向右倒,任何“缺水的容器”只能由它左边的容器补给。
因此从左到右维护“当前容器能否达到 ”是充分且必要的。
若扫描结束都没有出现缺水情况,则一定可以达成目标。
算法步骤
- 计算总和 ,得到平均值
- 初始化当前剩余水量为
- 对 从 到 :
- 若 :输出
"NO"并结束 - 否则,将多余的水 加到 上,并将 设为
- 若 :输出
- 若循环结束,输出
"YES"
复杂度分析
- 时间复杂度: 每个测试用例
- 空间复杂度: 存储数组(可优化到 但没必要)
- 总 不超过 ,足够快
示例验证
以第三个测试用例 为例:
- ,,
- :,多余 给 →
- :,多余 给 →
- :,多余 给 →
- :,无需操作
最终全部为 ,输出"YES"
代码(已给出)
#include <iostream> #include <vector> using namespace std; void solve() { int n; cin >> n; vector<long long> a(n); long long sum = 0; for (int i = 0; i < n; i++) { cin >> a[i]; sum += a[i]; } long long k = sum / n; for (int i = 0; i < n - 1; i++) { if (a[i] < k) { cout << "NO" << endl; return; } a[i + 1] += a[i] - k; a[i] = k; } cout << "YES" << endl; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) { solve(); } return 0; }
总结
本题的关键在于:
- 发现只能向右倒水的限制
- 从左到右贪心处理多余的水
- 一旦发现某容器水量不足平均值,则不可能成功
这就是 CF 1931B - Make Equal 的标准解法。
-
- 1
信息
- ID
- 6409
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者