思路
这道题显然需要二分一个平均值,
问题是小数怎么二分呢?
我们可以定义 l , r , m i d l,r,mid l,r,mid 为double类型,
并在判断时加上一个eps即可。(eps是在函数程序中事先声明的常量,是控制迭代精度的,相当于微积分里面的无限小值)
这个问题解决了,我们发现还有一个问题:
判断当前二分到的平均值是否满足条件是 O ( n 2 ) O(n^2) O(n2),会超时。
首先想到前缀和优化。
此时判断区间为 max s u m i − s u m i − j + 1 ( l < i ≤ n , j ≤ i − l ) \max{sum_i-sum_{i-j+1}} (l<i≤n,j≤i-l) maxsumi−sumi−j+1(l<i≤n,j≤i−l)
不难发现 j j j 只会在 1 1 1~ i − l i-l i−l 中循环比较,直接 max \max max 即可,可以省掉一个for循环。
然后注意让当前区间的 s u m i − j + 1 sum_{i-j+1} sumi−j+1 最小即可得到较优答案。
C o d e Code Code
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps=1e-6;
double ans=0,a[100010];
int n,k;
bool check(double x)
{
double b[100010];
for(int i=1; i<=n; i++)
b[i]=b[i-1]+(a[i]-x);
double minn=0,boss=-2147483647;
for(int i=k; i<=n; i++)
{
boss=max(boss,b[i]-minn);
minn=min(minn,b[i-k+1]);
}
if(boss>=0)
return 1;
else
return 0;
}
int main()
{
cin>>n>>k;
for(int i=1; i<=n; i++)
scanf("%lf",&a[i]);
double l=0,r=2000,mid=0;
while(l+eps<=r)
{
mid=(l+r)/2;
if(check(mid))
l=mid,ans=max(ans,mid);
else
r=mid;
}
cout<<int(r*1000);
return 0;
}