Water Balance(2100/贪心/双指针)

题目:http://codeforces.com/contest/1300/problem/E
题意:给定n个数 ( 1 < = n < = 1 e 6 ) (1<=n<=1e6) ,任意次操作,每次操作可以取任意连续子区间,使其该区间的数都变为区间的平均数。构造出字典序最小的序列。
参考:https://blog.csdn.net/qq_43627087/article/details/104249948
题解:要使字典序最小,则要求从左到右开始,每个数都取最小。对于当前数 p o s pos ,往后取区间,使得平均下来,当前数 a [ p o s ] a[pos] 最小化,设有多个边界 r 1 , r 2 , . . . r k r1,r2,...rk 都能使a[pos]最小化,那么我们只需贪心地取最小的 r r ,从左往右计算,时间复杂度为 O ( n 2 ) O(n^2) ,超时。
考虑优化,边读边合并,如果当前区间比前面的区间平均值更大,那么将该区间与前面的区间合并。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000010;
int n,x;

struct node{
	int num;
	double val;
	node(){}
	node(int _num,double _val){
		num=_num,val=_val;
	}
}tmp;
node a[maxn];

int main(){
	scanf("%d",&n);
	int cnt=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		a[cnt++]=node(1,1.0*x);
		while(cnt>1&&a[cnt-1].val*a[cnt-2].num<a[cnt-2].val*a[cnt-1].num){
			tmp=node(a[cnt-1].num+a[cnt-2].num,a[cnt-1].val+a[cnt-2].val);
			cnt--;a[cnt-1]=tmp;
		}
	}
	double val;
	for(int i=0;i<cnt;i++){
		x=a[i].num;
		val=a[i].val/x;
		while(x--){
			printf("%.10f\n",val);
		}
	}
	return 0;
}
/*
12
8 10 4 6 6 4 1 2 2 6 9 5
*/ 
发布了71 篇原创文章 · 获赞 1 · 访问量 2804

猜你喜欢

转载自blog.csdn.net/weixin_43918473/article/details/104262313