CodeForces_1299C Water Balance(贪心)

Water Balance

time limit per test:3 seconds
memory limit per test:256 megabytes
Problem Description

There are n water tanks in a row, i-th of them contains ai liters of water. The tanks are numbered from 1 to n from left to right.

You can perform the following operation: choose some subsegment [ l , r ] ( 1 ≤ l ≤ r ≤ n ) [l,r] (1≤l≤r≤n) [l,r](1lrn), and redistribute water in tanks l,l+1,…,r evenly. In other words, replace each of al,al+1,…,ar by a l + a l + 1 + . . . + a r r − l + 1 \frac{a_l+a_{l+1}+...+a_r}{r-l+1} rl+1al+al+1+...+ar. For example, if for volumes [1,3,6,7] you choose l=2,r=3, new volumes of water will be [1,4.5,4.5,7]. You can perform this operation any number of times.

What is the lexicographically smallest sequence of volumes of water that you can achieve?

Input

The first line contains an integer n (1≤n≤106) — the number of water tanks.

The second line contains n integers a1,a2,…,an (1≤ai≤106) — initial volumes of water in the water tanks, in liters.

Because of large input, reading input as doubles is not recommended.

Output

Print the lexicographically smallest sequence you can get. In the i-th line print the final volume of water in the i-th tank.

Sample Input

10
3 9 5 5 1 7 5 3 8 7

Sample Output

3.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
7.500000000
7.500000000

题意

有n桶水,每个桶初始有ai单位的水,先可以将一段连续的桶内的水平均,即选择区间 [ l , r ] [l,r] [l,r],l到r内所有的水将变为 a l + a l + 1 + . . . + a r r − l + 1 \frac{a_l+a_{l+1}+...+a_r}{r-l+1} rl+1al+al+1+...+ar。可以进行任意次的以上操作,求使桶内水的字典序尽量小。

题解:

需要字典序最小,那么靠前的桶内的水需要尽量的少。所以可以选择每次暴力,求需要合并到那个桶,才能使平均值最小。但这样是N2的,所以考虑有没有更好的做法。
显然答案是一个非递减的序列,因为如果有一个桶内的水,比前面桶内的水少,那么他们平均一下,字典序就可以更小。所以可以考虑进行这种操作:
维护一个栈,每个元素代表一段区间,区间维护三个参数l,r,ave,代表编号l到r的桶里,平均值为ave。
依次考虑每个初始桶,首先将初始的桶放入栈中, l = r = i l=r=i l=r=i, a v e = a i ave = a_i ave=ai。如果栈顶的平均值小于栈顶前面的那个平均值,即 s t a c k [ t o p ] . a v e < s t a c k [ t o p − 1 ] . a v e stack[top].ave < stack[top-1].ave stack[top].ave<stack[top1].ave,则合并区间(这样可以保证字典序更小)。
遍历完所有桶后,栈中的区间即为结果。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
 
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 1000100;
const int mod = 1000000007;
struct node{
	int l, r;
	double ave;
}p[maxn];
int a[maxn];
double ans[maxn], sum[maxn];

int main()
{
	int n, i, j, k, top = 0;
	scanf("%d", &n);
	sum[0] = 0;
	for(i=1;i<=n;i++){
		scanf("%d", &a[i]);
		sum[i] = sum[i-1]+a[i];
	}
	for(i=1;i<=n;i++){
		p[++top].l = i;
		p[top].r = i;
		p[top].ave = a[i];
		while(top>=2 && p[top].ave < p[top-1].ave)
		{
			p[top-1].ave = (sum[p[top].r]-sum[p[top-1].l-1])/(p[top].r-p[top-1].l+1);
			p[top-1].r = p[top].r;
			top--;
		}
	}
	while(top){
		for(j=p[top].l;j<=p[top].r;j++)
			ans[j] = p[top].ave;
		top--;
	}
	for(i=1;i<=n;i++)
		printf("%.10f\n", ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值