P1721 [NOI2016]国王饮水记

题目描述

跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1号城市中。

跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王又体恤地将分配给他的水也给跳蚤国居民饮用,这导致跳蚤国王也经常喝不上水。

于是,跳蚤国在每个城市都修建了一个圆柱形水箱,这些水箱完全相同且足够高。一个雨天后,第 i个城市收集到了高度为 hi 的水。由于地理和天气因素的影响,任何两个不同城市收集到的水高度互不相同。

跳蚤国王也请来蚂蚁工匠帮忙,建立了一个庞大的地下连通系统。跳蚤国王每次使用地下连通系统时,可以指定任意多的城市,将这些城市的水箱用地下连通系统连接起来足够长的时间之后,再将地下连通系统关闭。由连通器原理,这些城市的水箱中的水在这次操作后会到达同一高度,并且这一高度等于指定的各水箱高度的平均值。

由于地下连通系统的复杂性,跳蚤国王至多只能使用 k次地下连通系统。跳蚤国王请你告诉他,首都 1号城市水箱中的水位最高能有多高?

输入输出格式

输入格式:

输入的第一行包含 3个正整数 n,k,p,分别表示跳蚤国中城市的数量,跳蚤国王能使用地下连通系统的最多次数,以及你输出的答案要求的精度。p 的含义将在输出格式中解释。

接下来一行包含 n个正整数,描述城市的水箱在雨后的水位。其中第 i 个 正整数 hi表示第 i 个城市的水箱的水位。保证 hi 互不相同,1\le h_i \le10^51hi105

输出格式:

输出仅一行一个实数,表示 1 号城市的水箱中的最高水位。

这个实数只可以包含非负整数部分、小数点和小数部分。其中非负整数部分为必需部分,不加正负号。若有小数部分,则非负整数部分与小数部分之间以一个小数点隔开。若无小数部分,则不加小数点。

你输出的实数在小数点后不能超过 2p 位,建议保留至少 p位。数据保证参考答案与真实答案的绝对误差小于 10^{-2p}102p

你的输出被判定为正确当且仅当你的输出与参考答案的绝对误差小于 $10^{−p}$。此外,每个测试点你将有可能获得部分分。

如果你的输出与参考答案的绝对误差不小于 10^{-p}10p 但小于 10^{-5}105,你可以获得该测试点 40% 的分数。

输入输出样例

输入样例#1:

3 1 3
1 4 3
输出样例#1:  
2.666667

说明

由于至多使用一次地下连通系统,有以下 5 种方案:

  1. 不使用地下连通系统:此时 1 号城市的水箱水位为 1。

  2. 使用一次连通系统,连通 1、2 号:此时 11 号城市的水箱水位为 5/2。

  3. 使用一次连通系统,连通 1、3 号:此时 1 号城市的水箱水位为 2/2。

  4. 使用一次连通系统,连通 2、3号:此时 1 号城市的水箱水位为 1。

  5. 使用一次连通系统,连通 1、2、3号:此时 11 号城市的水箱水位为 8/3。

为保证答案精度,我们一般需要尽可能地在运算过程中保留超过 p位小数。我们可以证明,在各个子任务的参考算法中都能保证,在任何时候始终保留 6/5p位小数时,对任何输入得到的输出,与参考答案的绝对误差都小于 10^−p。

为了方便选手处理高精度小数,我们提供了定点高精度小数类。选手可以根据自己的需要参考与使用该类,也可以不使用该类。其具体的使用方法请参考下发的文档 decimal.pdf。

转载自www.cnblogs.com/ljh2000-jump/p/6376109.html

代码(经过o2优化):

// luogu-judger-enable-o2
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
typedef long long LL;
 
// ---------- decimal lib start ----------
const int PREC = 3000;//!!!
class Decimal {
    public:
        Decimal();
        Decimal(const std::string &s);
        Decimal(const char *s);
        Decimal(int x);
        Decimal(long long x);
        Decimal(double x);
         
        bool is_zero() const;
         
        // p (p > 0) is the number of digits after the decimal point
        std::string to_string(int p) const;
        double to_double() const;
         
        friend Decimal operator + (const Decimal &a, const Decimal &b);
        friend Decimal operator + (const Decimal &a, int x);
        friend Decimal operator + (int x, const Decimal &a);
        friend Decimal operator + (const Decimal &a, long long x);
        friend Decimal operator + (long long x, const Decimal &a);
        friend Decimal operator + (const Decimal &a, double x);
        friend Decimal operator + (double x, const Decimal &a);
         
        friend Decimal operator - (const Decimal &a, const Decimal &b);
        friend Decimal operator - (const Decimal &a, int x);
        friend Decimal operator - (int x, const Decimal &a);
        friend Decimal operator - (const Decimal &a, long long x);
        friend Decimal operator - (long long x, const Decimal &a);
        friend Decimal operator - (const Decimal &a, double x);
        friend Decimal operator - (double x, const Decimal &a);
         
        friend Decimal operator * (const Decimal &a, int x);
        friend Decimal operator * (int x, const Decimal &a);
         
        friend Decimal operator / (const Decimal &a, int x);
         
        friend bool operator < (const Decimal &a, const Decimal &b);
        friend bool operator > (const Decimal &a, const Decimal &b);
        friend bool operator <= (const Decimal &a, const Decimal &b);
        friend bool operator >= (const Decimal &a, const Decimal &b);
        friend bool operator == (const Decimal &a, const Decimal &b);
        friend bool operator != (const Decimal &a, const Decimal &b);
         
        Decimal & operator += (int x);
        Decimal & operator += (long long x);
        Decimal & operator += (double x);
        Decimal & operator += (const Decimal &b);
         
        Decimal & operator -= (int x);
        Decimal & operator -= (long long x);
        Decimal & operator -= (double x);
        Decimal & operator -= (const Decimal &b);
         
        Decimal & operator *= (int x);
         
        Decimal & operator /= (int x);
         
        friend Decimal operator - (const Decimal &a);
         
        // These can't be called
        friend Decimal operator * (const Decimal &a, double x);
        friend Decimal operator * (double x, const Decimal &a);
        friend Decimal operator / (const Decimal &a, double x);
        Decimal & operator *= (double x);
        Decimal & operator /= (double x);
         
    private:
        static const int len = PREC / 9 + 1;
        static const int mo = 1000000000;
         
        static void append_to_string(std::string &s, long long x);
         
        bool is_neg;
        long long integer;
        int data[len];
         
        void init_zero();
        void init(const char *s);
};
 
Decimal::Decimal() {
    this->init_zero();
}
 
Decimal::Decimal(const char *s) {
    this->init(s);
}
 
Decimal::Decimal(const std::string &s) {
    this->init(s.c_str());
}
 
Decimal::Decimal(int x) {
    this->init_zero();
     
    if (x < 0) {
        is_neg = true;
        x = -x;
    }
     
    integer = x;
}
 
Decimal::Decimal(long long x) {
    this->init_zero();
     
    if (x < 0) {
        is_neg = true;
        x = -x;
    }
     
    integer = x;
}
 
Decimal::Decimal(double x) {
    this->init_zero();
     
    if (x < 0) {
        is_neg = true;
        x = -x;
    }
     
    integer = (long long)x;
    x -= integer;
     
    for (int i = 0; i < len; i++) {
        x *= mo;
        if (x < 0) x = 0;
        data[i] = (int)x;
        x -= data[i];
    }
}
 
void Decimal::init_zero() {
    is_neg = false;
    integer = 0;
    memset(data, 0, len * sizeof(int));
}
 
bool Decimal::is_zero() const {
    if (integer) return false;
    for (int i = 0; i < len; i++) {
        if (data[i]) return false;
    }
    return true;
}
 
void Decimal::init(const char *s) {
    this->init_zero();
     
    is_neg = false;
    integer = 0;
     
    // find the first digit or the negative sign
    while (*s != 0) {
        if (*s == '-') {
            is_neg = true;
            ++s;
            break;
        } else if (*s >= 48 && *s <= 57) {
            break;
        }
        ++s;
    }
     
    // read the integer part
    while (*s >= 48 && *s <= 57) {
        integer = integer * 10 + *s - 48;
        ++s;
    }
     
    // read the decimal part
    if (*s == '.') {
        int pos = 0;
        int x = mo / 10;
         
        ++s;
        while (pos < len && *s >= 48 && *s <= 57) {
            data[pos] += (*s - 48) * x;
            ++s;
            x /= 10;
            if (x == 0) {
                ++pos;
                x = mo / 10;
            }
        }
    }
}
 
void Decimal::append_to_string(std::string &s, long long x) {
    if (x == 0) {
        s.append(1, 48);
        return;
    }
     
    char _[30];
    int cnt = 0;
    while (x) {
        _[cnt++] = x % 10;
        x /= 10;
    }
    while (cnt--) {
        s.append(1, _[cnt] + 48);
    }
}
 
std::string Decimal::to_string(int p) const {
    std::string ret;
     
    if (is_neg && !this->is_zero()) {
        ret = "-";
    }
     
    append_to_string(ret, this->integer);
     
    ret.append(1, '.');
     
    for (int i = 0; i < len; i++) {
        // append data[i] as "%09d"
        int x = mo / 10;
        int tmp = data[i];
        while (x) {
            ret.append(1, 48 + tmp / x);
            tmp %= x;
            x /= 10;
            if (--p == 0) {
                break;
            }
        }
        if (p == 0) break;
    }
     
    if (p > 0) {
        ret.append(p, '0');
    }
     
    return ret;
}
 
double Decimal::to_double() const {
    double ret = integer;
     
    double k = 1.0;
    for (int i = 0; i < len; i++) {
        k /= mo;
        ret += k * data[i];
    }
     
    if (is_neg) {
        ret = -ret;
    }
     
    return ret;
}
 
bool operator < (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return a.is_neg && (!a.is_zero() || !b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return false;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return false;
    }
}
 
bool operator > (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return !a.is_neg && (!a.is_zero() || !b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return false;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return false;
    }
}
 
bool operator <= (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return a.is_neg || (a.is_zero() && b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return true;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return true;
    }
}
 
bool operator >= (const Decimal &a, const Decimal &b) {
    if (a.is_neg != b.is_neg) {
        return !a.is_neg || (a.is_zero() && b.is_zero());
    } else if (!a.is_neg) {
        // a, b >= 0
        if (a.integer != b.integer) {
            return a.integer > b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] > b.data[i];
            }
        }
        return true;
    } else {
        // a, b <= 0
        if (a.integer != b.integer) {
            return a.integer < b.integer;
        }
        for (int i = 0; i < Decimal::len; i++) {
            if (a.data[i] != b.data[i]) {
                return a.data[i] < b.data[i];
            }
        }
        return true;
    }
}
 
bool operator == (const Decimal &a, const Decimal &b) {
    if (a.is_zero() && b.is_zero()) return true;
    if (a.is_neg != b.is_neg) return false;
    if (a.integer != b.integer) return false;
    for (int i = 0; i < Decimal::len; i++) {
        if (a.data[i] != b.data[i]) return false;
    }
    return true;
}
 
bool operator != (const Decimal &a, const Decimal &b) {
    return !(a == b);
}
 
Decimal & Decimal::operator += (long long x) {
    if (!is_neg) {
        if (integer + x >= 0) {
            integer += x;
        } else {
            bool last = false;
            for (int i = len - 1; i >= 0; i--) {
                if (last || data[i]) {
                    data[i] = mo - data[i] - last;
                    last = true;
                } else {
                    last = false;
                }
            }
            integer = -x - integer - last;
            is_neg = true;
        }
    } else {
        if (integer - x >= 0) {
            integer -= x;
        } else {
            bool last = false;
            for (int i = len - 1; i >= 0; i--) {
                if (last || data[i]) {
                    data[i] = mo - data[i] - last;
                    last = true;
                } else {
                    last = false;
                }
            }
            integer = x - integer - last;
            is_neg = false;
        }
    }
    return *this;
}
 
Decimal & Decimal::operator += (int x) {
    return *this += (long long)x;
}
 
Decimal & Decimal::operator -= (int x) {
    return *this += (long long)-x;
}
 
Decimal & Decimal::operator -= (long long x) {
    return *this += -x;
}
 
Decimal & Decimal::operator /= (int x) {
    if (x < 0) {
        is_neg ^= 1;
        x = -x;
    }
     
    int last = integer % x;
    integer /= x;
     
    for (int i = 0; i < len; i++) {
        long long tmp = 1LL * last * mo + data[i];
        data[i] = tmp / x;
        last = tmp - 1LL * data[i] * x;
    }
     
    if (is_neg && integer == 0) {
        int i;
        for (i = 0; i < len; i++) {
            if (data[i] != 0) {
                break;
            }
        }
        if (i == len) {
            is_neg = false;
        }
    }
     
    return *this;
}
 
Decimal & Decimal::operator *= (int x) {
    if (x < 0) {
        is_neg ^= 1;
        x = -x;
    } else if (x == 0) {
        init_zero();
        return *this;
    }
     
    int last = 0;
    for (int i = len - 1; i >= 0; i--) {
        long long tmp = 1LL * data[i] * x + last;
        last = tmp / mo;
        data[i] = tmp - 1LL * last * mo;
    }
    integer = integer * x + last;
     
    return *this;
}
 
Decimal operator - (const Decimal &a) {
    Decimal ret = a;
    // -0 = 0
    if (!ret.is_neg && ret.integer == 0) {
        int i;
        for (i = 0; i < Decimal::len; i++) {
            if (ret.data[i] != 0) break;
        }
        if (i < Decimal::len) {
            ret.is_neg = true;
        }
    } else {
        ret.is_neg ^= 1;
    }
    return ret;
}
 
Decimal operator + (const Decimal &a, int x) {
    Decimal ret = a;
    return ret += x;
}
 
Decimal operator + (int x, const Decimal &a) {
    Decimal ret = a;
    return ret += x;
}
 
Decimal operator + (const Decimal &a, long long x) {
    Decimal ret = a;
    return ret += x;
}
 
Decimal operator + (long long x, const Decimal &a) {
    Decimal ret = a;
    return ret += x;
}
 
Decimal operator - (const Decimal &a, int x) {
    Decimal ret = a;
    return ret -= x;
}
 
Decimal operator - (int x, const Decimal &a) {
    return -(a - x);
}
 
Decimal operator - (const Decimal &a, long long x) {
    Decimal ret = a;
    return ret -= x;
}
 
Decimal operator - (long long x, const Decimal &a) {
    return -(a - x);
}
 
Decimal operator * (const Decimal &a, int x) {
    Decimal ret = a;
    return ret *= x;
}
 
Decimal operator * (int x, const Decimal &a) {
    Decimal ret = a;
    return ret *= x;
}
 
Decimal operator / (const Decimal &a, int x) {
    Decimal ret = a;
    return ret /= x;
}
 
Decimal operator + (const Decimal &a, const Decimal &b) {
    if (a.is_neg == b.is_neg) {
        Decimal ret = a;
        bool last = false;
        for (int i = Decimal::len - 1; i >= 0; i--) {
            ret.data[i] += b.data[i] + last;
            if (ret.data[i] >= Decimal::mo) {
                ret.data[i] -= Decimal::mo;
                last = true;
            } else {
                last = false;
            }
        }
        ret.integer += b.integer + last;
        return ret;
    } else if (!a.is_neg) {
        // a - |b|
        return a - -b;
    } else {
        // b - |a|
        return b - -a;
    }
}
 
Decimal operator - (const Decimal &a, const Decimal &b) {
    if (!a.is_neg && !b.is_neg) {
        if (a >= b) {
            Decimal ret = a;
            bool last = false;
            for (int i = Decimal::len - 1; i >= 0; i--) {
                ret.data[i] -= b.data[i] + last;
                if (ret.data[i] < 0) {
                    ret.data[i] += Decimal::mo;
                    last = true;
                } else {
                    last = false;
                }
            }
            ret.integer -= b.integer + last;
            return ret;
        } else {
            Decimal ret = b;
            bool last = false;
            for (int i = Decimal::len - 1; i >= 0; i--) {
                ret.data[i] -= a.data[i] + last;
                if (ret.data[i] < 0) {
                    ret.data[i] += Decimal::mo;
                    last = true;
                } else {
                    last = false;
                }
            }
            ret.integer -= a.integer + last;
            ret.is_neg = true;
            return ret;
        }
    } else if (a.is_neg && b.is_neg) {
        // a - b = (-b) - (-a)
        return -b - -a;
    } else if (a.is_neg) {
        // -|a| - b
        return -(-a + b);
    } else {
        // a - -|b|
        return a + -b;
    }
}
 
Decimal operator + (const Decimal &a, double x) {
    return a + Decimal(x);
}
 
Decimal operator + (double x, const Decimal &a) {
    return Decimal(x) + a;
}
 
Decimal operator - (const Decimal &a, double x) {
    return a - Decimal(x);
}
 
Decimal operator - (double x, const Decimal &a) {
    return Decimal(x) - a;
}
 
Decimal & Decimal::operator += (double x) {
    *this = *this + Decimal(x);
    return *this;
}
 
Decimal & Decimal::operator -= (double x) {
    *this = *this - Decimal(x);
    return *this;
}
 
Decimal & Decimal::operator += (const Decimal &b) {
    *this = *this + b;
    return *this;
}
 
Decimal & Decimal::operator -= (const Decimal &b) {
    *this = *this - b;
    return *this;
}
 
// ---------- decimal lib end ----------
 
const int MAXN = 8011;
Decimal ans;
int n,k,p,h[MAXN],dui[MAXN],head,tail,from[MAXN][20],s[MAXN];
double f[MAXN][20];
 
struct Point{
    double x,y;
}ljh,b[MAXN];
 
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}
 
inline double K(Point q,Point qq){
    return (qq.y-q.y)/(qq.x-q.x);
}
 
inline Decimal calc(int i,int j){
    if(j==0) return h[1];
    return ( calc(from[i][j],j-1) + s[i]-s[from[i][j]] ) / (i-from[i][j]+1);
}
 
inline void work(){
    n=getint(); k=getint(); p=getint(); h[1]=getint();
    for(int i=2;i<=n;i++) { h[i]=getint(); if(h[i]<=h[1]) i--,n--; }
    sort(h+1,h+n+1); for(int i=1;i<=n;i++) s[i]=s[i-1]+h[i];
    k=min(k,n); for(int i=1;i<=n;i++) f[i][0]=h[1];//不操作的话就是1本身
    int lim;
    if(k>14) lim=14; else lim=k;
    for(int j=1;j<=lim;j++) {//最多lim个长度超过1的区间
        head=tail=0; dui[tail]=1;
        b[1].x=0; b[1].y=s[1]-f[1][j-1];
        for(int i=2;i<=n;i++) {
            ljh.x=i; ljh.y=s[i];
            while(head<tail && K(b[dui[head]],ljh)<K(b[dui[head+1]],ljh)) head++;
            b[i].x=i-1; b[i].y=s[i]-f[i][j-1]; from[i][j]=dui[head];
            f[i][j]=s[i]-s[dui[head]]+f[dui[head]][j-1]; f[i][j]/=(double)(i-dui[head]+1);
            while(head<tail && K(b[dui[tail-1]],b[dui[tail]])>K(b[dui[tail]],b[i])) tail--;
            dui[++tail]=i;
        }
    }
 
    //要选lim个长度大于等于1的区间
    //而如果k>14则必须要选若干长度只有1的区间,否则我每次都可以选长度大于1的区间,也就是k(lim)次
 
    int u=n-(k-lim);//最后k-lim个必定是只选1个
    //所以u就是长度大于等于1操作区间的结束位置,必然也是最后一个决策点
 
    //枚举从u往前的所有区间中操作多少次
    double suan=0; int star;
    for(int j=0;j<=lim;j++) if(f[u][j]>suan) suan=f[u][j],star=j;
    ans=calc(u,star);
    for(int i=u+1;i<=n;i++) ans=(ans+h[i])/2;
    cout<<ans.to_string(p*2);
}
 
int main()
{
    work();
    return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值