1.4.6 Best Cow Fences(solution+discuss)

大家好,这又是一道二分题,首先来看题面。

 

Description

Farmer John's farm consists of a long row of NNN ( 1≤N≤1051 \le N \le 10^51≤N≤105)fields. Each field contains a certain number of cows, 1≤ncows≤20001 \le ncows \le 20001≤ncows≤2000.

FJ wants to build a fence around a contiguous group of these fields in order to maximize the average number of cows per field within that block.

The block must contain at least FFF (1≤F≤N1 \le F \le N1≤F≤N) fields, where FFF given as input.

Calculate the fence placement that maximizes the average, given the constraint.

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

Input

  • Line 1: Two space-separated integers, NNN and FFF.

  • Lines 222..N+1N+1N+1: Each line contains a single integer, the number of cows in a field. Line 2 gives the number of cows in field 1,line 3 gives the number in field 2, and so on.

Output

  • Line 1:A single integer that is  1000  \;1000\;1000times the maximal average.Do not perform rounding, just print the integer that is 1000×ncows/n1000\times ncows/n1000×ncows/n fields.

Sample Input 1

10 6 
6  
4  
2  
10  
3  
8  
5  
9  
4  
1 

Sample Output 1

6500 

Hint

1  ≤  N  ≤  100,0001  \le  N  \le  100,0001  ≤  N  ≤  100,000

1  ≤  ncows  ≤  20001  \le  ncows  \le  20001  ≤  ncows  ≤  2000

#include<bits/stdc++.h>
using namespace std;
int n,f;
double line[100010];//正整数数列A 
double sum[100010];//前缀和 
double b[100010];//储存数列A减去当前数值
/*
题解:对平均数进行二分,找出减去当前平均数的前缀和sum[i]-min_val的值得到答案ans来判断可否实现。-Megumin
*/
int main()
{
	scanf("%d %d", &n, &f);
	for (int i = 1; i <= n; i++) 
	{
		scanf("%lf", &line[i]);
	}

	double eps = 1e-5;
	double l = -1e6, r = 1e6;
	while(r-l > eps)
	{
		double mid = (l+r) / 2;
		for (int i = 1; i <= n; i++) 
			b[i] = line[i] - mid;

		for (int i = 1; i <= n; i++) 
			sum[i]=sum[i-1]+b[i];//obj 1前缀和处理 
		//以下是记录 
		double ans = -1e10;//保存当前的答案 
		double min_val = 1e10;//保存当前的前缀和最小值
		for (int i = f; i <= n; i++) 
		{
			min_val = min(min_val, sum[i - f]);//obj 2当处理i的时候我们最短可以减掉哪里的sum值? 
			ans = max(ans, sum[i] - min_val);//obj 3答案是怎么算出来的? 
		}
		
		if(ans>=0)//obj 4二分处理 
			l=mid; 
		else
			r=mid;
	}

	printf("%d",(int)(r*1000));

	return 0;
}

需要思考三个问题:

1、

for (int i = 1; i <= n; i++) 
			sum[i]=sum[i-1]+b[i];//obj 1前缀和处理 
		//以下是记录 
		double ans = -1e10;//保存当前的答案 
		double min_val = 1e10;//保存当前的前缀和最小值
		for (int i = f; i <= n; i++) 
		{
			min_val = min(min_val, sum[i - f]);//obj 2当处理i的时候我们最短可以减掉哪里的sum值? 
			ans = max(ans, sum[i] - min_val);//obj 3答案是怎么算出来的? 
		}

这里sum[i-1]+b[i]是想干什么?b[i]是干什么用的?

2、

		if(ans>=0)//obj 4二分处理 
			l=mid; 
		else
			r=mid;

l,r在二分的时候为什么不用加一or减一?

 想了解详情,笔者之后会更新,请您多多关注~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

irrationality

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值