二分答案#贪心
1. 完整
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN=1e5+50,MAXX=1e10;
const double MINN=1e-6;LL N,P,a[MAXN],b[MAXN];
double sum=0,Ans=-1;double cost(LL a[],LL b[],LL L,LL R,double x){double sum=0;for(int i=L;i<=R;i++){double temp=a[i]*x;if(temp>b[i]) sum+=temp-b[i];}return sum;
}void Init(){scanf("%lld%lld",&N,&P);for(int i=1;i<=N;i++) scanf("%lld%lld",&a[i],&b[i]),sum+=a[i];
}
void Solve(){if(sum<=P) return;double l,mid,r;for(l=0,r=MAXX,mid=(l+r)/2;r-l>MINN;mid=(l+r)/2){double temp=cost(a,b,1,N,mid);if(P*mid>=temp) l=mid;else r=mid-MINN;}Ans=l;
}void Print(){printf("%.10lf\n",Ans);
}int main()
{Init();Solve();Print();return 0;
}
2. 全局变量声明
LL N, P, a[MAXN], b[MAXN];
double sum = 0, Ans = -1;
N
用于存储设备的数量,P
存储充电宝每秒的充电量;a
数组存储每个设备的能量消耗速率,b
数组存储每个设备初始的能量;sum
用于后续计算所有设备能量消耗速率的总和;Ans
用于存储最终计算得到的最长使用时间,初始化为-1
表示还未计算出有效结果 。
3. cost
函数
double cost(LL a[], LL b[], LL L, LL R, double x) {double sum = 0;for (int i = L; i <= R; i++) {double temp = a[i] * x;if (temp > b[i]) sum += temp - b[i];}return sum;
}
- 功能:计算在时间
x
秒内,从设备L
到设备R
这些设备总共需要额外补充的能量。因为每个设备每秒消耗a[i]
能量,x
秒就消耗a[i] * x
能量,如果这个消耗超过了设备初始存储的b[i]
能量,那么超出部分就需要充电宝来补充,把所有设备超出的部分累加起来就是sum
,也就是这段时间内充电宝需要提供的总充电量 。 - 参数说明:
a[]
是设备能量消耗速率数组,b[]
是设备初始能量数组,L
和R
限定计算的设备范围,x
是假设的使用时间。 - 返回值:返回在时间
x
内,指定设备区间需要充电宝补充的总能量。
4. Init
函数
void Init() {scanf("%lld%lld", &N, &P);for (int i = 1; i <= N; i++) scanf("%lld%lld", &a[i], &b[i]), sum += a[i];
}
- 功能:用于初始化数据,从标准输入读取设备数量
N
和充电宝每秒充电量P
,然后依次读取每个设备的能量消耗速率a[i]
和初始能量b[i]
,同时累加所有设备的能量消耗速率到sum
中,为后续判断是否能无限使用做准备 。
5. Solve
函数
void Solve() {if (sum <= P) return;double l, mid, r;for (l = 0, r = MAXX, mid = (l + r) / 2; r - l > MINN; mid = (l + r) / 2) {double temp = cost(a, b, 1, N, mid);if (P * mid >= temp) l = mid;else r = mid - MINN;}Ans = l;
}
- 功能:核心的计算逻辑,用于求解设备最长共同使用时间。
- 首先判断
sum
(所有设备能量消耗速率总和)是否小于等于P
(充电宝每秒充电量),如果是,说明充电宝提供的电量足以弥补所有设备的消耗,设备可以无限使用,直接返回(此时Ans
保持初始的-1
,后续Print
函数会输出-1
)。 - 如果
sum > P
,则通过二分查找来确定最长使用时间。二分查找的思路是:假设使用时间为mid
,计算在这mid
时间内,所有设备需要充电宝补充的总能量temp
(通过cost
函数计算),然后看充电宝在mid
时间内总共能提供的电量P * mid
是否能满足temp
。如果能满足(P * mid >= temp
),说明可以尝试更长的使用时间,调整二分查找的左边界l = mid
;如果不能满足,说明当前假设的mid
太大了,需要调小,调整右边界r = mid - MINN
。不断重复这个过程,直到二分查找的区间长度小于MINN
,此时认为找到了足够精确的结果,把左边界l
的值赋给Ans
,作为最终的最长使用时间 。
- 首先判断