• POJ 2018 Best Cow Fences(二分答案)


    题目链接:http://poj.org/problem?id=2018

    题目给了一些农场,每个农场有一定数量的奶牛,农场依次排列,问选择至少连续排列F个农场的序列,使这些农场的奶牛平均数量最大,求最大数量*1000/农场的个数。

    思路:题目是求是否存在一个长度不小于F的子段,使得平均数最大。

    1.用二分法从给定数据的最小平均数到最大平均数进行二分枚举,每次枚举的平均值为mid,那么子段的每一个元素减去mid值再求和应当大于0,否则不满足题意,这样可以不断地二分,最终找到最大的mid值

    2.判断子段和可以利用前缀和,每次二分的时候,先行让每个元素减去mid值,再求一个前缀和sum[i],前缀和大于0则说明平均数大于mid

    3.从 i = F开始枚举到i = N,每次都要记录当前0到(i - N)的最小前缀和minval,因为当sum[ i ] - minval时,才可能存在长度不小于F且子段和最大的序列。

    4.因为是在实数域上的二分,所以要注意精度问题,精度eps一般取1e-(k+2),此题k为3(1000是10的3次方)

    AC代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    using namespace std;
    double a[100002],b[100002],sum[100002]; 
    int main(){
    	int N,F;
    	scanf("%d%d",&N,&F);
    	for(int i = 1;i<=N;i++){
    		scanf("%lf",&a[i]);
    	}
    	double l = -1e6, r = 1e6;
    	while(l+1e-5 < r){//注意精度问题 
    		double mid = (l + r)/2; 
    		for(int i = 1;i<=N;i++){
    			b[i] = a[i] - mid;//依次减去枚举的平均值mid 
    		}
    		for(int i = 1;i<=N;i++){
    			sum[i] = (b[i] + sum[i-1]);//求前缀和 
    		}
    		double ans = -1e10,minVal = 1e10;
    		for(int i = F;i<=N;i++){
    			minVal = min(minVal,sum[i-F]);//记录当前最小前缀和
    			                              //且保证子段大于等于F 
    			ans = max(ans,sum[i] - minVal); //求子段最大和 
    		}
    		if(ans >= 0){
    			l = mid ;
    		}
    		else{
    			r = mid ;
    		}
    	}
    	cout<<int(r*1000);
    	return 0;
    }
  • 相关阅读:
    各地电信运营商插广告赚钱,北京联通也不甘落后
    也谈Server Limit DOS的解决方案
    Still Believe
    无奈小虫何
    好朋有也有类别
    无为而治
    青鸟随想
    落寞时分
    网站开发学习路线和资料
    C++实例 添加快捷键表
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12129629.html
Copyright © 2020-2023  润新知