1 条题解
-
0
PA 2019 Runda 2 Herbata 题解
题目分析
这道题要求判断是否可以通过无限次的分割和混合操作,将初始状态的水杯 转化为目标状态 。
关键操作:
- 分割:将一杯水按任意比例分成多杯,温度保持不变
- 混合:将两杯水混合,新温度为体积加权平均温度
解题思路
核心观察
- 守恒量:总热量(体积 × 温度)在操作过程中守恒
- 温度范围:混合后的温度一定在原来两杯水的温度之间
- 问题转化:问题等价于判断能否通过重新分配热量来达到目标状态
算法设计
代码采用了贪心匹配的方法:
主要步骤:
- 将初始状态 和目标状态 分别存储
- 按温度排序初始状态和目标状态
- 使用双指针贪心匹配:
- 每次取当前温度最低的初始水和目标水
- 用尽可能多的热量从初始水转移到目标水
- 检查过程中是否出现热量不足的情况
代码详解
#include <bits/stdc++.h> using namespace std; using ll = long long; constexpr ll N = 1000010; ll n; struct Nd { ll x, y; // x: 体积, y: 温度 friend ll operator<(const Nd &a, const Nd &b) { return a.y < b.y; // 按温度排序 } } a[N], b[N]; void solve() { cin >> n; // 读入数据:初始状态 (l_i, a_i) 和目标状态 (l_i, b_i) for (ll i = 1, x, y, z; i <= n; i++) { cin >> x >> y >> z; a[i] = {x, y}; // 初始:体积x,温度y b[i] = {x, z}; // 目标:体积x,温度z } // 按温度排序 sort(a + 1, a + n + 1); sort(b + 1, b + n + 1); ll i = 1, j = 1; // 双指针 ll s = 0; // 热量差(当前累积的热量盈余/赤字) while (i <= n && j <= n) { // 取当前可转移的最小体积 ll w = min(a[i].x, b[j].x); // 计算热量变化:从温度a[i].y的水转移到温度b[j].y的目标 // 热量差 = (目标温度 - 初始温度) × 体积 s += (b[j].y - a[i].y) * w; // 如果热量差为负,说明热量不足,无解 if (s < 0) { cout << "NIE\n"; return; } // 更新剩余体积 if (!(a[i].x -= w)) i++; if (!(b[j].x -= w)) j++; } // 检查是否所有水都处理完且热量平衡 cout << (i > n && j > n && !s ? "TAK\n" : "NIE\n"); } int main() { ios::sync_with_stdio(0), cin.tie(0); ll T; cin >> T; while (T--) solve(); return 0; }算法原理
为什么这样是正确的?
-
热量守恒:
- 总热量 = Σ(体积 × 温度) 在操作中保持不变
- 如果初始总热量 ≠ 目标总热量,肯定无解
-
温度可行性:
- 混合操作只能产生介于原温度之间的温度
- 如果目标温度不在初始温度范围内,需要热量转移
-
贪心策略:
- 从低温开始匹配,确保热量总是从高温向低温转移
- 如果出现热量赤字,说明无法达到目标
关键变量解释
-
s:累积的热量差s > 0:有多余热量可以用于升温s < 0:热量不足,无法达到目标温度s = 0:热量恰好平衡
-
(b[j].y - a[i].y) * w:转移热量- 如果为正:需要消耗热量来升温
- 如果为负:释放热量可用于其他升温
样例分析
样例1:TAK
输入:2 2 1 4 2 5 2初始:2体积1°C + 2体积5°C = 总热量12
目标:2体积4°C + 2体积2°C = 总热量12
热量守恒,温度在范围内,有解样例2:NIE
输入:2 1 4 3 1 5 4初始:1体积4°C + 1体积5°C = 总热量9
目标:1体积3°C + 1体积4°C = 总热量7
总热量不守恒,无解复杂度分析
- 时间复杂度:,主要来自排序
- 空间复杂度:,存储初始和目标状态
正确性证明
定理:算法输出TAK当且仅当存在可行解
证明:
-
必要性:如果算法输出TAK,那么:
- 总热量守恒(最终s=0)
- 所有温度转移都可行(过程中s≥0)
- 因此存在可行的操作序列
-
充分性:如果存在可行解,那么:
- 总热量必须守恒
- 必须能够通过混合操作实现温度转换
- 贪心策略会找到这样的方案
总结
这道题的关键在于:
- 识别热量守恒这一核心物理原理
- 将问题转化为热量转移的可行性判断
- 使用贪心算法高效验证可行性
算法巧妙地利用了排序和双指针技术,在 时间内解决了问题,能够处理大规模输入。
- 1
信息
- ID
- 4853
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者