CF1299C Water Balance

简要题意

你有一个序列$\{a\}$,你的每次操作可以把一段区间里的数全部变成这个区间的平均数,求能得到的字典序最小的序列

分析

我们发现字典序最小时显然$\{a_i\}$单调不降

那么我们可以维护一个单调栈,栈里维护的值$\{l,r,avr\}$,表示该段区间的左端点、右端点、平均值

每次插入$\{i,i,a_i\}$,然后暴力循环取出栈顶的两个节点$x, y$($y$在$x$后插入),如果满足$y.avr<x.avr$则合并$x,y$,直到不能合并为止(具体细节可以看代码)

最后把栈中记录的值输出即可

代码

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
41
42
#include <bits/stdc++.h>

#define R register
#define ll long long
#define sum(a, b, mod) (((a) + (b)) % mod)

const int MaxN = 1e6 + 10;

struct node
{
int l, r;
double sum, len;
};

int n;
double a[MaxN];
std::vector<node> vec;

int main()
{
int tmp;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &tmp), a[i] = tmp;
for (int i = 1; i <= n; i++)
{
vec.push_back((node){i, i, a[i], 1});
while (vec.size() >= 2 && (vec[vec.size() - 2].sum / vec[vec.size() - 2].len) >= (vec[vec.size() - 1].sum / vec[vec.size() - 1].len))
{
node x = (node){vec[vec.size() - 2].l, vec[vec.size() - 1].r, vec[vec.size() - 2].sum + vec[vec.size() - 1].sum, vec[vec.size() - 1].r - vec[vec.size() - 2].l + 1.0};
vec.pop_back(), vec.pop_back(), vec.push_back(x);
}
}
for (int i = 0; i < vec.size(); i++)
{
for (int j = vec[i].l; j <= vec[i].r; j++)
a[j] = (vec[i].sum / vec[i].len);
}
for (int i = 1; i <= n; i++)
printf("%.10lf\n", a[i]);
return 0;
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×