题目链接
题意给你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);
}
}
}
}