- 最佳牛围栏
https://www.acwing.com/problem/content/description/104/
步骤:
1、二分处理
2、前缀和处理
3、找最大的前缀和是否大于0
二分原理:因为所有平均值肯定介于0~2000之中,不可能大于最大值所以可以二分搜索出一个mid值判断是否是满足要求的平均值
(ai+ai+1+…aj )/i+j >= mid (j-i>-f)
移项并在在mid乘一个j+i 再除以一个j+i,可以视作把每个ai-aj的元素都减了一个mid值,然后判断是否大于0(这样就剩下了除以一个j+i的步骤不用考虑精度)
用前缀和更快的算出大于f范围内的和,用一个minv来记录0-i之间最小值,通过递增i来不断更新最小值,j初始化为f保证了j,i间距大于f(由于minv不一定是i位置的值,所以平均值的长度就肯定大于或者等于f)
注意:实数二分r=mid/l=mid即可且mid类型要开double
由于题目要求乘1000所以精度一定是大于1e-3的,可以往1e-4或者1e-5开所以二分结束条件即为r-l>1e-4
#include<iostream>
#include<algorithm>
using namespace std;
int n,f;
const int N = 1000010;
int cows[N];
double sums[N];
bool calc(double ave)
{
for(int i = 1;i<=n;i++)sums[i] = sums[i-1] + cows[i] - ave;
double minv = 1000010;
for(int i = 0,j = f;j<=n;i++,j++)
{
minv = min(minv,sums[i]);
if(sums[j] >= minv)return true;
}
return false;
}
int main()
{
cin>>n>>f;
for(int i = 1;i<=n;i++)cin>>cows[i];
double l = 0,r = 2000;
while(r - l >1e-4)
{
double mid = (l+r)/ 2;
if(calc(mid))
l = mid;
else
r = mid;
}
cout<<int(r*1000)<<endl;
}