Best Cow Fence(二分)poj2018

题目传送门

题意 :给定正整数数列A,求一个平均数最大的,长度不小于L的(连续的)子段。

分析 :如果没有 “平均数”“长度不小于L” 这两个限制,那么这就是一个最大子段和的问题。我们可以用二分的方法找到一个数,假设这个数是最大的平均数,将数列A中所有位置减去这个数,那么这个题就变成将数列A减去一个数,求大于0的字段和(长度不小于L)。解决了“平均数”问题再来看“子段不小于L”这个限制,我们可以用前缀和的方法在线的求出任意一段子段和,用sum表示数列A的前缀和,所以我们从第L个开始(可以直接从长度为L开始,可以免去长度小于L
的情况)for循环每次增加一个长度,记录最小sum(假设现在循环到了L+2个,那么sum[1]和sum[2]中找出那个最小的数,再用sum[L+2]-min得到的就是最大子段和)也是增加一个。

大致代码
*注意:用cin会tle 坑了我好久QAQ

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1e5+5;
double a[N],sum[N],temp[N];
int main()
{
	double eps = 1e-5,ans=0;
	int n,L;
	double l=1e8,r=-1; 
	memset(a,0,sizeof a);
	memset(sum,0,sizeof sum);
	memset(temp,0,sizeof temp);
	scanf("%d%d",&n,&L);
	for(int i=1;i<=n;i++){
		scanf("%lf",&a[i]);
		l=min(l,a[i]);
		r=max(r,a[i]);
	} 
	while(l+eps<r){
		double mid = (l+r)/2;
		for(int i=1;i<=n;i++) temp[i] = a[i]-mid;
		for(int i=1;i<=n;i++) sum[i] = temp[i]+sum[i-1];
		double minl=1e8,maxl=-1;
		int size=0;
		for(int i=L;i<=n;i++){
			minl=min(minl,sum[size++]);
			maxl=max(maxl,sum[i]-minl); 
		}
		if(maxl>=0) l=mid;
		else r=mid;
	}
	cout<<int(r*1000);
	
	return 0;
 } 
发布了7 篇原创文章 · 获赞 6 · 访问量 297

猜你喜欢

转载自blog.csdn.net/weixin_43626741/article/details/104387369