E - Water Balance
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].
In the second sample, you can’t get any lexicographically smaller sequence.
题目大意
给你一串数字,你可以对连续的数字取平均值,然后保证取完之后这一串数字的平均值最小;
解题思路
假设说现在有两个数字,x1,x2;如果x2小于x1;那么我们是不是就让x1和 x2取平均值,如果不是那么就不管对吧?,然后我们将x1,x2想成两个区间,只是这个区间的数值都是一样的,那么我还可以根据这个策略进行贪心,一旦发现后面的前面的数值小,就把他们合成一块,然后继续向下走;
代码
#include<bits/stdc++.h>
using namespace std;
const int mx=1000100;
double a[mx];
double len[mx],st[mx];//分别存这一块的长度和平均值
int p;//记录有几块
int main()
{
int n;scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&a[i]);
}
for(int i=1;i<=n;i++){
st[++p]=a[i];//记录这一块的平均值
len[p]=1;//其长度开始时唯一
while(p>1&&st[p]<st[p-1]){//去更新前面的数值,如果比前面的小就进行 合并
st[p-1]=(st[p]*len[p]+st[p-1]*len[p-1])/(len[p]+len[p-1]);//将两块区间合并
len[p-1]=len[p-1]+len[p];//更新长度
p--;//块数也相应的减一
}
}
for(int i=1;i<=p;i++)//输出
{
for(int j=1;j<=len[i];j++)
{
printf("%.9lf\n",st[i]);
}
}
return 0;
}