E. Water Balance

一场cf的题,题目链接

题目大意是给你一串数字,你可以选择任意区间,让其中的每一个数的值是整个区间和的平均数,求最小的字典序。

这个题需要让前面的序列越小越好即寻找 r 令sum(1-r)/r最小,然后让1取代r继续类推,,暴力的写法T了;

一开始暴力的写了一发,T了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 double s[1000005] = {0.0}, sum[1000005] ={0.0};
 4 
 5 int main()
 6 {
 7     int n;
 8     scanf("%d", &n);
 9     for(int i = 1; i <= n; i++){
10         scanf("%lf", &s[i]);
11         sum[i] = sum[i-1] + s[i];
12     }
13     for(int i = 0; i < n; i++){
14         double minn = 1000000000.0;
15         int k, pos;
16         for(k = i + 1; k <= n; k++){
17             if((sum[k] - sum[i]) / (k - i) < minn){
18                 minn = 1.0 * (sum[k] - sum[i]) / (k - i);
19                 pos = k;
20                 if(minn == 1) break;
21             }
22         }
23         for(int k = i + 1; k <= pos; k++) s[k] = minn;
24         i = pos - 1;
25     }
26     for(int i = 1; i <= n; i++){
27         printf("%.9lf\n", s[i]);
28     }
29 
30 }

借鉴了大佬们的写法,太妙了

再引入s[i]的同时更新前端的序列;

#include<bits/stdc++.h>
using namespace std;
double s[1000005] = {0.0}, sum[1000005] ={0.0}, p[1000005] = {0}, q[1000005] = {0};
int top = 0;
int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%lf", &s[i]);
        //sum[i] = sum[i-1] + s[i];
    }
    for(int i = 1; i <= n; i++){
        double sum = s[i];
        int k = 1;
        while(top && sum*q[top] <= k*p[top]){
              sum += p[top], k += q[top],top--;
        }
        p[++top] = sum, q[top] = k;
       // cout << p[top] << " " << q[top] << " " << top << endl;
    }
    for(int i = 1; i <= top; i++){
        for(int j = 1; j <= q[i]; j++){
            printf("%.9lf\n", 1.0 * p[i] / q[i]);
        }
    }
}

 

posted @ 2020-02-10 20:04  jvruodejxt  阅读(80)  评论(0编辑  收藏  举报

Contact with me