zoukankan      html  css  js  c++  java
  • [Noi2016]国王饮水记

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    跳蚤国有 n 个城市,伟大的跳蚤国王居住在跳蚤国首都中,即 1 号城市中。跳蚤国最大的问题就是饮水问题,由于首都中居住的跳蚤实在太多,跳蚤国王又体恤地将分配给他的水也给跳蚤国居民饮用,这导致跳蚤国王也经常喝不上水。于是,跳蚤国在每个城市都修建了一个圆柱形水箱,这些水箱完全相同且足够高。一个雨天后,第 i 个城市收集到了高度为 hi 的水。由于地理和天气因素的影响,任何两个不同城市收集到的水高度互不相同。跳蚤国王也请来蚂蚁工匠帮忙,建立了一个庞大的地下连通系统。跳蚤国王每次使用地下连通系统时,可以指定任意多的城市,将这些城市的水箱用地下连通系统连接起来足够长的时间之后,再将地下连通系统关闭。由连通器原理,这些城市的水箱中的水在这次操作后会到达同一高度,并且这一高度等于指定的各水箱高度的平均值。由于地下连通系统的复杂性,跳蚤国王至多只能使用 k 次地下连通系统。跳蚤国王请你告诉他,首都 1 号城市水箱中的水位最高能有多高?

    n<=8000 hi<=10^5

    至少保留p位小数 p<=3000

    提供了一个高精度小数类  

    首先考虑只保留大于1号城市的高度,并且发现从小到大合并比较优秀 所以按照从小到大排序 求出前缀和Hi

    然后每次都计算太麻烦了,所以用一个trick,先用long double计算出转移路径再计算答案 (题解里面一套分数类啥的可以直接做)

    列出转移方程$f[k][i]=max(frac{f[k-1][j]+si-sj}{i-j+1})$ 考虑维护(j-1,sj-f[k-1][j])的下凸壳,发现它满足决策单调性 于是复杂度降低至$O(n^{2}+np)$

    但是根据题解里面一系列的结论,每次取的长度不同且递减,长度大于1的最多只有14个,所以先dp出14层,然后剩下的直接两两合并就行了。复杂度O(14n+np)

    // This is a test program with decimal lib
    
    #include <cstdlib>
    #include <cstring>
    #include <string>
    
    // ---------- decimal lib start ----------
    
    const int PREC = 2100;
    
    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 = 500;
            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 ----------
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    #define MN 8000
    #define ld long double
    
    inline int read()
    {
        int x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    int n , m , k , K , p , h[MN + 5] , Pre , top , From[17][MN + 5];
    ld f[17][MN + 5];
    struct P
    {
        int x; ld y;    
        P(int _x = 0,ld _y = 0): x(_x) , y(_y) {}
        friend ld Calc(P a , P b)
        {
            return (b.y - a.y) / (b.x - a.x);
        }    
    };
    
    struct MyQueue
    {
        P q[MN + 5];int top , tail;
        void Clear(){ q[top = tail = 1] = P( -1 , -Pre);}    
        void ins(P t)
        {
            while(top > tail && Calc(q[top-1] , q[top]) > Calc(q[top] , t)) --top;
            q[ ++top ] = t;
        }
        int Query(P t)
        {
            while(top > tail && Calc(q[tail] , t) < Calc(q[tail + 1] , t)) ++tail;    
            return q[tail].x + 1; 
        }
    }Q;
    
    Decimal Ans;
    
    void Dfs(int t , int x)
    {
        if(!t) return;
        Dfs( t - 1 , From[t][x] );
        Ans = ( Ans + h[x] - h[From[t][x]] ) / (x - From[t][x] + 1);
    }
    
    int main() {
        m = read(); K = read(); p = read(); Pre = read();
        for(int i = 1 , j;i < m ;++i)
            if((j = read()) > Pre) h[++n] = j;
        sort(h+1 , h + n + 1); K = min(K , n); k = min(K , 14);
        for(int i = 1 ;i <= n ;++i) h[i] += h[i-1] , f[0][i] = Pre;h[0] = -Pre;
        for(int j = 1;j <= k ;++j)
        {
            Q.Clear();
            for(int i = 1 ;i <= n ; ++i)
            {
                From[j][i] = Q.Query(P(i , h[i]));
                f[j][i] = (f[j - 1][From[j][i]] + h[i] - h[ From[j][i] ]) / (i - From[j][i] + 1);
                Q.ins(P(i - 1 , h[i] - f[j - 1][i]));
            }
        }
        Ans = Decimal ( Pre ); h[0] = 0;
        Dfs ( k , n - (K - k) );
        for(int i = n - (K - k) + 1;i <= n ; ++i) Ans = (Ans + h[i] - h[i-1]) / 2;
        cout << Ans.to_string(p + 2);
        return 0;
    }
  • 相关阅读:
    顺序表的C语言实现
    Nginx模块开发(5)————开发简单的HTTP过滤模块
    python集合(set)
    python——封装、解构
    python——杨辉三角
    python——bytes、bytearray
    python算法——求10万以内的质数
    python算法——打印菱形、对等三角、闪电
    python字符串操作
    python—冒泡排序
  • 原文地址:https://www.cnblogs.com/FallDream/p/Noi2016d2t2.html
Copyright © 2011-2022 走看看