Best Cow Fences

POJ

题意:给定\(N(N<=10^5)\)个正整数的数列,求一个平均数最大且长度不小于m的连续的子段.输出子段和乘上1000之后的整数即可.

分析:实数域上的二分答案,每次直接二分平均数mid,然后令序列中的每个数减去该mid,对得到的新数列求前缀和sum,最后判定最大子段和是否非负即可.

至于如何求出新数列的最大子段和?用一个变量\(minn\)记录最小的\(sum[j]\),每次i递增时,与\(sum[i-m]\)\(min\)来更新\(minn\),然后用\(sum[i]-minn\)更新最大子段和\(ans\)即可.

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
inline int read() {
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=100005;
int n,m,a[N];
double b[N],sum[N];
inline bool check(double mid){
	for(int i=1;i<=n;++i)b[i]=a[i]*1.0-mid;
	for(int i=1;i<=n;++i)sum[i]=sum[i-1]+b[i];
	double ans=-1e9,minn=1e9;
	for(int i=m;i<=n;++i){
		minn=min(minn,sum[i-m]);
		ans=max(ans,sum[i]-minn);
	}
	if(ans>=0)return true;
	else return false;
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)a[i]=read();
	double l=0.0,r=1e9,eps=1e-6;
	while(r-l>eps){
		double mid=(l+r)/2.0;
		if(check(mid))l=mid;
		else r=mid;
	}
	printf("%d\n",(int)(r*1000));
    return 0;
}

posted on 2019-07-22 21:17  PPXppx  阅读(140)  评论(0编辑  收藏  举报