CF68B题解

题目传送门

思路:

错误方案:

一个一个去试可不可以,这样试的过程是O\left ( n \right ),检查是否合法的过程至少也是O\left ( n \right ),总的时间复杂度至少是O\left (n ^{2} \right ),一定会超时。

正确方案:

先想一个问题,如果最后每个剩下x点电量,那么可不可以每个剩下比x少的电量呢?

一定是可以的。

因为每传一次都会损失一些电量,所以我们只需要多传几次,每个的电量就剩下小于x的电量了。

所以,我们就可以使用二分,这样时间复杂度至少是O\left ( nlog_{n}\right ),可以AC。

再想想如何让检查的时间复杂度降为O\left ( n \right )

我们可以定义一个变量,如果一个数大于目标的电量,那么这个变量就加上多出来的电量,减去损失的电量,表示可以传输这么多的电量,如果一个数小于目标的电量,那么就减去比目标电量少的电量,表示消耗了这些电量。最后如果这个变量为负数,就表示需要消耗的比多余的要多,是不可以的,就return false;如果大于等于零,就表示正好或者有多余的电量(多余的电量可以传来传去传没),是可以的,就return true;

还需要注意一点,这道题需要小数二分小数二分链接),大部分变量都要用double

时间复杂度:O\left ( nlog_{n}\right )

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<set>
#include<map>
using namespace std;
double n,m,a[201000];
bool check(double mid){
	double sum=0;
	for(int i=1;i<=n;i++){
		if(a[i]>mid){
			sum+=(a[i]-mid)-(a[i]-mid)*(m/100);
		}else{
			sum-=(mid-a[i]);
		}
	}return sum>=0;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>a[i];
	double l=0,r=20000000,mid;
	while(r-l>=0.000000001){
		mid=(l+r)/2;
		if(check(mid)){
			l=mid;
		}else{
			r=mid;
		}
	}printf("%.9lf",r); 
	return 0;
}
  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值