Codeforces Round #618 (Div. 2)(E. Water Balance)(分块)

Codeforces Round #618 (Div. 2)(E. Water Balance)(分块)

time limit per test3 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
judge: 点我跳转

Description

There are n n n water tanks in a row, i i i-th of them contains a i a_i ai liters of water. The tanks are numbered from 1 1 1 to n n 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 l,l+1,…,r l,l+1,,r evenly. In other words, replace each of a l , a l + 1 , … , a r a_l,a_{l+1},…,a_r 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 ] [1,3,6,7] [1,3,6,7] you choose l = 2 , r = 3 l=2,r=3 l=2,r=3, new volumes of water will be [ 1 , 4.5 , 4.5 , 7 ] [1,4.5,4.5,7] [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?

As a reminder:

A sequence a a a is lexicographically smaller than a sequence b b b of the same length if and only if the following holds: in the first (leftmost) position where a a a and b b b differ, the sequence a has a smaller element than the corresponding element in b b b.

Input

The first line contains an integer n ( 1 ≤ n ≤ 1 0 6 ) n (1≤n≤10^6) n(1n106) — the number of water tanks.

The second line contains n integers a 1 , a 2 , … , a n ( 1 ≤ a i ≤ 1 0 6 ) a_1,a_2,…,a_n (1≤a_i≤10^6) a1,a2,,an(1ai106) — 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 i i-th tank.

Your answer is considered correct if the absolute or relative error of each ai does not exceed 1 0 − 9 10^{−9} 109.

Formally, let your answer be a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an, and the jury’s answer be b 1 , b 2 , … , b n b_1,b_2,…,b_n b1,b2,,bn. Your answer is accepted if and only if ∣ a i − b i ∣ m a x ( 1 , ∣ b i ∣ ) ≤ 1 0 − 9 \frac{|a_i−b_i|}{max(1,|b_i|)}≤10^{−9} max(1,bi)aibi109 for each i i i.

Examples

input
4
7 5 5 7
output
5.666666667
5.666666667
5.666666667
7.000000000
input
5
7 8 8 10 12
output
7.000000000
8.000000000
8.000000000
10.000000000
12.000000000
input
10
3 9 5 5 1 7 5 3 8 7
output
3.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
5.000000000
7.500000000
7.500000000

Note

In the first sample, you can get the sequence by applying the operation for subsegment [ 1 , 3 ] [1,3] [1,3].

In the second sample, you can’t get any lexicographically smaller sequence.

题解

暴力肯定过不了。

一个比较巧妙的方法是把区间问题转化成“块”的问题,然后贪心地求解。

每次取数组中的一个元素放到一个新的“块”中,然后比较这个块和前一个块的大小(即当前块的平均值),如果比前一个小,那么说明把当前块和前一个块合并后平均值是变小的,然后再把合并后的块与现在的前一个块进行比较,以此类推,直到当前块的值不比前一个块的值小。

找到最后块的排列即是答案。

代码

#include <bits/stdc++.h>
#define m_p make_pair
#define maxn 1000005
#define _for(i, a) for(int i = 0; i < (a); ++i)
using namespace std;

template<class T>inline void rd(T &res) {
	char c; T flag = 1;
	while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = -1; res = c - '0';
	while ((c = getchar()) >= '0'&&c <= '9') res = res * 10 + c - '0'; res *= flag;
}

int n, a[maxn];
vector< pair< double, int > > bl;

void init() {
	bl.clear();
}

void sol() {
	init();
	_for(i, n) {
		bl.push_back(m_p(a[i], 1));
		while (bl.size() > 1) {
			pair< double, int > &t = bl[bl.size() - 2], ne = bl.back();
			if (t.first <= ne.first) break;
			t = m_p((t.first * t.second + ne.first * ne.second) / (t.second + ne.second), t.second + ne.second);
			bl.pop_back();
		}
	}
	_for(i, bl.size()) {
		_for(j, bl[i].second) {
			printf("%.9f\n", bl[i].first);
		}
	}
	cout << "\n\n";
}

int main() {
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	//freopen("in.txt", "r", stdin);

	while (cin >> n) {
		_for(i, n) rd(a[i]);
		sol();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值