题目背景
翻译自 ROIR 2023 D2T1。
用于铺设地铁隧道的盾构机有 n 个发动机。所有发动机是并联的,所以所有发动机两端的电压都相同。
每个发动机有两种模式,假设所有发动机接收到的电压都为 x,则当 x≤zi 时第 i 个发动机在第一模式下工作,否则它在第二模式下工作。
第 i 个发动机在第一模式下的单位电流为 ai,在第二模式下的单位电流为 bi。所以,根据 P=UI,当发动机处于第一模式时,每增加 1 单位电压,其功率增加 ai 单位;当发动机处于第二模式时,每增加 1 单位电压,其功率增加 bi 单位。换句话说,当电压为 x 单位电压,如果第 i 个发动机处于第一模式下,它以 ai×x 的单位功率运行;如果处于第二模式下,它以 ai×zi+bi×(x−zi) 的单位功率运行。
题目描述
最少需要提供多大的电压(电压需要是整数),才能使所有发动机的总功率大于或等于 p?
输入格式
第一行输入两个整数 n 和 p。
接下来的 n 行,每行包含三个整数 zi,ai,bi。
输出格式
输出一个整数表示最小电压。
输入输出样例
输入 #1复制
1 6 4 1 2
输出 #1复制
5
输入 #2复制
3 15 2 3 3 4 2 1 5 2 2
输出 #2复制
3
说明/提示
本题使用捆绑测试。
子任务编号 | 分值 | 特殊性质 |
---|---|---|
1 | 20 | n=1 |
2 | 20 | ai,bi≤100,p≤105 |
3 | 20 | 所有 zi 均相等 |
4 | 20 | n≤2 |
5 | 20 |
对于 100% 的数据,1≤n≤100,1≤p≤10^12,1≤zi≤10^9,1≤ai,bi≤10^4。
分析:
这是一个明显的二分答案的题,x也就是电压越大,功率越强,所以电压越大,就越容易达到目标,所以成功区,也就是达到目标的区域在右边,题目所求的就是成功区最左侧的端点。
代码和注释:
#include<bits/stdc++.h>
using namespace std;
long long n, p;
long long a[105], z[105], b[105];
// 检查电压为 x 时总功率是否 >= p
bool check(long long x) {
long long sum = 0;
for (long long i = 0; i < n; i++) {
if (x > z[i]) {
// 第二模式
sum += a[i] * z[i]; // 第一阶段的功率
sum += (x - z[i]) * b[i]; // 第二阶段的功率
} else {
// 第一模式
sum += a[i] * x;
}
}
return sum >= p;
}
// 二分查找最小满足条件的电压
long long search() {
long long l = -1, r = p + 1; // 初始范围 [0, p+1]
while (l + 1 < r) {
long long mid = (l + 1 + r) >> 1; // 等价于 (l + r + 1)/2
if (check(mid)) {
r = mid; // 可行,尝试更小的电压
} else {
l = mid; // 不可行,必须增大电压
}
}
cout << r; // 输出最小可行电压
return 0;
}
int main() {
cin >> n >> p;
for (long long i = 0; i < n; i++) {
cin >> z[i] >> a[i] >> b[i];
}
search();
return 0;
}