题目传送门
思路:
错误方案:
一个一个去试可不可以,这样试的过程是,检查是否合法的过程至少也是,总的时间复杂度至少是,一定会超时。
正确方案:
先想一个问题,如果最后每个剩下点电量,那么可不可以每个剩下比少的电量呢?
一定是可以的。
因为每传一次都会损失一些电量,所以我们只需要多传几次,每个的电量就剩下小于的电量了。
所以,我们就可以使用二分,这样时间复杂度至少是,可以AC。
再想想如何让检查的时间复杂度降为。
我们可以定义一个变量,如果一个数大于目标的电量,那么这个变量就加上多出来的电量,减去损失的电量,表示可以传输这么多的电量,如果一个数小于目标的电量,那么就减去比目标电量少的电量,表示消耗了这些电量。最后如果这个变量为负数,就表示需要消耗的比多余的要多,是不可以的,就return false;如果大于等于零,就表示正好或者有多余的电量(多余的电量可以传来传去传没),是可以的,就return true;
还需要注意一点,这道题需要小数二分(小数二分链接),大部分变量都要用double
时间复杂度:
代码:
#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;
}