Water Balance(CF618E/C)(单调栈)

文章目录

题目

给你一个数列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n ,每次选择一段区间 [ l , r ] [l,r] ,将其中每个数变为他们的平均数,问最小字典序?
1 n 1 0 6 , 1 a i 1 0 9 1\le n\le 10^6,1\le a_i\le10^9

思路

TM傻逼题
发现 i 、i 前的操作不会改变 i i 前缀和 ,记前缀和为 p i p_i ,一次修改操作相当于将

p i = p l 1 + p r p l 1 r ( l 1 ) ( i l + 1 ) p_i=p_{l-1}+\frac{p_r-p_{l-1}}{r-(l-1)}*(i-l+1)

( i , p i ) (i,p_i) 看成点后,这TM不就是两点连线吗
求字典序最小然后就是维护一个下凸壳,单调栈即可(不会的学学斜率优化)

代码

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
inline int read() {
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define eps 1e-10
#define MAXN 1000000
#define INF 0x3f3f3f3f
double p[MAXN+5];
int Stk[MAXN+5],tp;
int main(){
	int n=read();
	for(int i=1;i<=n;i++)
		p[i]=p[i-1]+read();
	Stk[++tp]=0;
	for(int i=1;i<=n;i++){
		while(tp>=2&&(p[i]-p[Stk[tp]])/(i-Stk[tp])<(p[i]-p[Stk[tp-1]])/(i-Stk[tp-1]))
			tp--;
		Stk[++tp]=i;
	}
	for(int i=2;i<=tp;i++){
		double tmp=(p[Stk[i]]-p[Stk[i-1]])/(Stk[i]-Stk[i-1]);
		for(int j=Stk[i-1]+1;j<=Stk[i];j++)
			printf("%.10lf\n",tmp);
	}
	return 0;
}

反省

一定要多寻找题目特殊点,考试不要慌(老毛病又犯了)

猜你喜欢

转载自blog.csdn.net/qq_37555704/article/details/104244096