zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    codevs 1115 开心的金明
    POJ 1125 Stockbroker Grapevine
    POJ 2421 constructing roads
    codevs 1390 回文平方数 USACO
    codevs 1131 统计单词数 2011年NOIP全国联赛普及组
    codevs 1313 质因数分解
    洛谷 绕钉子的长绳子
    洛谷 P1276 校门外的树(增强版)
    codevs 2627 村村通
    codevs 1191 数轴染色
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12129629.html
Copyright © 2011-2022 走看看