给定一个长度为n的非负序列A,请你找出一个长度不小于L的子段(子段是序列A中一些连续的元素构成的集合),使得子段中数值的平均值最大。最终输出这个最大的平均值。
输入格式:
第一行两个整数n,L(1<=L<=n<=100,000)
以下n行,每行一个非负整数,表示序列A中每个元素的值。
输出格式:
一个整数,欲求的最大平均值乘以1000后的结果(注意不要四舍五入,直接输出)。
输入样例:
10 6
6
4
2
10
3
8
5
9
4
1
输出样例:
6500
源码
#include <bits/stdc++.h>
using namespace std;
int n = 0, L = 0;
double elements[100001] = {0};
double maxElement = 0, minElement = 1e9;
void myRead()
{
cin >> n >> L;
for (int i = 1; i <= n; ++i)
{
cin >> elements[i];
maxElement = max(elements[i], maxElement);
minElement = min(elements[i], minElement);
// maxElement = maxElement < elements[i] ? elements[i] : maxElement;
// minElement = minElement > elements[i] ? elements[i] : minElement;
}
}
bool myCheck(double average)
{
bool flag = false;
double sum[100001] = {0};
for (int i = 1; i <= n; ++i)
{
sum[i] = sum[i - 1] + (elements[i] - average);
}
// for (int i = 0; i < n; ++i)
// {
// cout << i + 1 << " : " << sum[i] << endl;
// }
double fronts = 1e9;
for (int i = L; i <= n; ++i)
{
fronts = min(fronts, sum[i - L]);
if (sum[i] - fronts > 0)
{
flag = true;
break;
}
}
return flag;
}
int main()
{
myRead();
double low = minElement, high = maxElement, answer = (low + high) / 2;
while (high - low > 1e-5)
{
// cout << "answer = " << answer << ", high = " << high << ", low = " << low << endl;
if (myCheck(answer))
{
low = answer;
}
else
{
high = answer;
}
answer = (low + high) / 2;
// cout << "---------------------" << endl;
}
// cout << "answer = " << answer << ", high = " << high << ", low = " << low << endl;
cout << (int)(high * 1000);
return 0;
}
心路历程
初体验
刚读完题目,感觉这道题熟悉,因为之前好像做过类似的题目,但是又想不起来是哪一道题。而且读完之后是想不到解题方法的,所以就去网上搜了别人的代码。看代码第一感觉是看不懂,别人的思路看不懂,代码也看不懂,看了好几篇,都很蒙,最终发现了其他人的文章中大多数都提到了二分答案这个词,这个词在之前没听说过,只听过二分查找,猜测是个算法名称,所以就去b站搜了关键字。
二分答案
二分答案是个算法。
首先先明白它适合什么问题:求最值问题(答案有一定的范围,并且明确的知道一对上下界)。
其次看看二分答案是什么:当一个求最值问题的求最值过程不好求解或者不会求解的时候,我们可以试着去猜答案,比如说这个最值问题的答案会出现在a到b之间,当我们猜c,发现c小了,那么下一步就可以猜一个c到b之间的数........直到猜到答案为止,有点像枚举,但又不是暴力枚举。
抽象的讲,二分答案法是把一个最值问题转化成了一个判断问题。
回归这道题
其实这道题就是求最大平均值,只不过有一个约束条件就是这组数要连续且长度不能小于L。先抛开约束条件不谈,平均值的范围一定是在这组数的最小值和最大值之间的,所以这就自然而然有了范围,正向解也不会解,所以就试试二分答案。
该吃饭了 不想写了....