码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 939E Maximize! (三分 || 尺取)

时间:2019-04-11 19:52:28      阅读:205      评论:0      收藏:0      [点我收藏+]

标签:src   event   pac   一段   temp   16px   现在   最小   top   

<题目链接>

题目大意:
给定一段序列,每次进行两次操作,输入1 x代表插入x元素(x元素一定大于等于之前的所有元素),或者输入2,表示输出这个序列的任意子集$s$,使得$max(s)-mean(s)$表示这个集合的最大值与平均值的最大差值。

解题分析:
首先,因为输入的$x$是非递减的,所以要使$max(s)-mean(s)$最大,肯定$max(s)$就是最后一个输入元素的大小。$x$已经确定了,现在就是尽可能的使$mean(s)$尽可能的小。如何使得平均值最小呢?肯定是从最前面的最小的元素开始选,因为最后一个元素是一定要选的(选做最大的元素),所以$mean(s)$函数必然是一个下凹的函数(在开始选小的元素时,平均值会被慢慢的拉低(因为一开始只有一个最大的元素),选到后面比较大的元素时,平均值又会逐渐上升)。所以我们可以用三分寻找max(s)-mean(s)函数的峰值。同时本题也可以用尺取来做,也是用来寻找峰值。

 

三分:

技术图片
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 5e5+5;
ll sum[N];

template<typename T>
inline void read(T&x){
    x=0;int f=1;char c=getchar();
    while(c<0 || c>9){ if(c==-)f=-1;c=getchar(); }
    while(c>=0 && c<=9){ x=x*10+c-0;c=getchar(); }
    x*=f;
}
inline double cal(int loc,int x){
    return (double)(sum[loc]+x)/(loc+1);
}
int main(){
    int q;read(q);
    int op,x,cnt=0;
    while(q--){
        read(op);
        if(op==1){
            read(x);
            sum[++cnt]=sum[cnt-1]+x;
        }else{
            //对前cnt-1个元素进行三分
            int l=1,r=cnt-1;
            while(l<r){
                int m1=(l+l+r)/3,m2=(l+r+r)/3;
                if(cal(m1,x)>=cal(m2,x)){
                    if(l==m1)break;
                    l=m1;
                }else{
                    if(r==m2)break;
                    r=m2;
                }
            }
            double ans=(double)(sum[l]+x)*1.0/(l+1);
            for(int i=l;i<=r;i++)ans=min(ans,(double)(sum[i]+x)/(i+1));     //因为最后[l,r]之间可能不只有一个元素 
            printf("%.10lf\n",x-ans);
        }
    }
}
View Code

 

尺取:

技术图片
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 5e5+5;
ll sum[N];

template<typename T>
inline void read(T&x){
    x=0;int f=1;char c=getchar();
    while(c<0 || c>9){ if(c==-)f=-1;c=getchar(); }
    while(c>=0 && c<=9){ x=x*10+c-0;c=getchar(); }
    x*=f;
}
inline double cal(int loc,int x){
    return (double)(sum[loc]+x)/(loc+1);
} 
int main(){
    int q;read(q);
    int op,x,cnt=0,top=0;
    while(q--){
        read(op);
        if(op==1){
            read(x);
            sum[++cnt]=sum[cnt-1]+x;
        }else{
            while(top<cnt){
                if(cal(top+1,x)<cal(top,x))top++;
                else break;
            }
            printf("%.10lf\n",x-cal(top,x));
        }
    }
}
View Code

 

Codeforces 939E Maximize! (三分 || 尺取)

标签:src   event   pac   一段   temp   16px   现在   最小   top   

原文地址:https://www.cnblogs.com/00isok/p/10691637.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!