Codeforces Round #618 (Div. 2)E. Water Balance(单调队列 + 思维)

题目链接
题意给你n个数,给你一种操作你可以选择一个区间,然后把这个区间的数变为(区间和)/(区间长度),之后让你求多次操作后字典序最小的数组a
解法:
1.如果当前的数字的数都是升序的,那么当前一定是字典序最小的,不需要操作直接输出.
2.有一种类似andrew求凸包的方法,我们一开始维护出一个前缀和,之后我们求出1-n之间中,求出操作[l, r]能够使得a[l]变小的左端点l,最后在队列对答案进行求出即可

#include<bits/stdc++.h>
#define M 200009
#define ll long long
#define ls u<<1
#define rs u<<1|1
#define sc scanf
#define pr printf
using namespace std;
const int maxn = 1e6 + 7;
double a[maxn];
int q[maxn],pos;
int n;
bool is_sort(){
	for(int i = 2; i <= n; i++){
		if(a[i] >= a[i - 1])continue;
		else return false;
	}
	return true;
} 
double across(int i , int j, int k){
	return (j - i)*(a[k] - a[i]) - (k - i)*(a[j] - a[i]);
}
int main(){
	sc("%d",&n);
	for(int i = 1; i <= n; i++)sc("%lf",&a[i]);
	if(is_sort()){
		for(int i = 1; i <= n; i++){
			if(i == 1)pr("%.9lf",a[i]);
			else pr(" %.9lf",a[i]);
		}
	}else{
		for(int i = 1; i <= n; i++)a[i] += a[i - 1];
		for(int i = 0; i <= n; i++){
			while(pos > 1 && across(q[pos - 2], q[pos - 1], i) <= 0)
			pos -- ;
			q[pos++] = i;
		}
		for(int i = 1; i < pos; i++){
			int len = q[i] - q[i - 1];
			double res = (double)(a[q[i]] - a[q[i - 1]])/len;
			while(len--){
				pr("%.9lf ",res);
			}
		}
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值