题目链接:平均数
分析
与洛谷这道题基本一样:平均数。只是差了一点精度上的处理。
因为如果能找到一段平均值超过k的区间,那必然能找到平均值大于k-1的区间,于是这题满足单调性。
设二分的答案是ans,若:
(
∑
i
j
a
[
i
]
)
/
(
j
−
i
)
⩾
a
n
s
(
j
−
i
+
1
⩾
k
)
(\sum_{i}^{j}a[i])/(j-i)\geqslant ans(j-i+1\geqslant k)
(i∑ja[i])/(j−i)⩾ans(j−i+1⩾k)
则有:
∑
i
j
a
[
i
]
⩾
a
n
s
∗
(
j
−
i
)
\sum_{i}^{j}a[i]\geqslant ans*(j-i)
i∑ja[i]⩾ans∗(j−i)
变形:
∑
i
j
a
[
i
]
−
a
n
s
∗
(
j
−
i
)
⩾
0
\sum_{i}^{j}a[i]-ans*(j-i)\geqslant 0
i∑ja[i]−ans∗(j−i)⩾0
合并:
∑
i
j
(
a
[
i
]
−
a
n
s
)
⩾
0
\sum_{i}^{j}(a[i]-ans)\geqslant 0
i∑j(a[i]−ans)⩾0
可以用前缀和记录区间值:
s
[
i
]
=
∑
j
=
1
i
(
a
[
i
]
−
a
n
s
)
s[i]=\sum_{j=1}^{i}(a[i]-ans)
s[i]=j=1∑i(a[i]−ans)
需要最大化
s
[
i
]
−
s
[
j
]
s[i]-s[j]
s[i]−s[j]
判断区间值减去二分的平均值之后是否非负,然后继续二分,不断接近最大平均值。
注意精度!
上代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,k;
double a[300001],s[300001],l,r,mid;
int pd(double ans)
{
s[0]=0;
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+(a[i]-mid);
}
double mn=0;
for(int i=k;i<=n;i++)
{
mn=min(mn,s[i-k]);
if(s[i]>=mn) return 1;//存在长度超过k的区间平均值超过0
}
return 0;
}
int main()
{
freopen("average.in","r",stdin);
freopen("average.out","w",stdout);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
l=0;r=1000000;
while(r-l>=0.000001)//保证精度
{
mid=(l+r)/2.0;
if(pd(mid)) l=mid;
else r=mid;
}
printf("%.6f",l);//l和r一样的,要保留小数!
return 0;
}