Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P1404 平均数

P1404 平均数

求最大平均数子串,考虑分数规划。

设当前有 $k$ 个数,第 $i$ 个数的值为 $w _ i$ ,当前二分值为 $x$ ,则
$$
\begin{aligned}
& \frac {\sum _ {i = 1} ^ k w _ i} k \ge x \\
\Longrightarrow & \sum _ {i = 1} ^ k w _ i \ge x k \\
\Longrightarrow & \sum _ {i = 1} ^ k w _ i - x \ge 0
\end{aligned}
$$
这道题还有一个要求,长度要大于等于 $m$ ,如果直接枚举子串的起始位置复杂度就已经是 $O(n ^ 2$ 了,这是不能接受的。考虑如何优化。我们将当前的 $w _ i - x$ 做前缀和,同时维护一个最小前缀和,如果当前的前缀和减去最小前缀和大于等于 $0$ ,即中间的一段就大于等于 $0$ 。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
const double eps = 1e-5;
int n, m;
double A[N], s[N];
bool check (double x)
{
for (int i = 1; i <= n; i++)
s[i] = s[i - 1] + A[i] - x;
double mn = 0;
for (int i = m; i <= n; i++)
{
mn = min(mn, s[i - m]);
if (s[i] >= mn)
return true;
}
return false;
}
int main ()
{
cin >> n >> m;
double l = 0, r = 0, mid;
for (int i = 1; i <= n; i++)
{
cin >> A[i];
r = max(r, A[i]);
}
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
cout << (int)(r * 1000);
return 0;
}