题目大意:
题目链接:https://jzoj.net/senior/#main/show/4256
给出包含一个
N
N
N个整数的数组
A
A
A。找出一段长度至少为
m
m
m的连续序列,最大化它的平均值。
思路:
很明显这道题的答案满足单调性。若可以找出一段区间的平均值超过
k
k
k,那么必然可以找到一段区间的平均值超过
k
−
1
k-1
k−1。
那么可以考虑二分答案。
设二分的答案为
a
n
s
ans
ans
若
(
∑
i
j
a
[
i
]
)
÷
(
j
−
i
)
≥
a
n
s
(
j
−
i
+
1
≥
m
)
(\sum^{j}_{i}a[i])\div (j-i)\geq ans(j-i+1\geq m)
(i∑ja[i])÷(j−i)≥ans(j−i+1≥m)
则
∑
i
j
a
[
i
]
≥
a
n
s
×
(
j
−
i
)
\sum^{j}_{i}a[i]\geq ans\times (j-i)
i∑ja[i]≥ans×(j−i)
∑
i
j
a
[
i
]
−
a
n
s
×
(
j
−
i
)
≥
0
\sum^{j}_{i}a[i]-ans\times (j-i)\geq 0
i∑ja[i]−ans×(j−i)≥0
∑
i
j
(
a
[
i
]
−
a
n
s
)
≥
0
\sum^{j}_{i}(a[i]-ans)\geq 0
i∑j(a[i]−ans)≥0
于是可以用前缀和
s
u
m
[
i
]
=
∑
j
=
1
i
(
a
[
i
]
−
a
n
s
)
sum[i]=\sum^{i}_{j=1}(a[i]-ans)
sum[i]=j=1∑i(a[i]−ans)
然后我们就要最大化
s
u
m
[
i
]
−
s
u
m
[
j
]
(
i
−
j
+
1
≥
m
)
sum[i]-sum[j](i-j+1\geq m)
sum[i]−sum[j](i−j+1≥m)
于是可以记录
m
a
x
(
s
u
m
[
k
]
)
(
k
∈
1
∼
j
−
1
)
max(sum[k])(k\in 1\sim j-1)
max(sum[k])(k∈1∼j−1)。然后枚举
i
i
i,判断最大化后可否超过0。
时间复杂度
O
(
n
l
o
g
n
)
O(n\ log\ n)
O(n log n)
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N=300010;
int n,m;
double l,r,mid,a[N],sum[N];
bool check(double ans)
{
sum[0]=0;
for (int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i]-mid;
double minn=0;
for (int i=m;i<=n;i++)
{
minn=min(minn,sum[i-m]); //记录最小值
if (sum[i]>=minn) return 1; //含有一个长度超过m的区间平均值超过0
}
return 0;
}
int main()
{
freopen("average.in","r",stdin);
freopen("average.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%lf",&a[i]);
l=0;
r=1000000;
while (r-l>=0.0001)
{
mid=(l+r)/2.0;
if (check(mid)) l=mid;
else r=mid;
}
printf("%lf",l);
return 0;
}