• Atcoder Beginner Contest 236 E Average and Median


    E. Average and Median

    题目大意

    给定一个数组\(x\),从中选出一些数字,要求俩俩相邻的数中必选一个,最大化平均值和中位数。

    中位数的定义为第\(\lceil \frac{n}{2} \rceil\)小的数。

    解题思路

    刚开始想着各种贪心DP都觉得不对,直接整平均数不一定有最优子结构。事后发现可以二分答案判断。

    就是二分平均数a,如果对于选出来的数\(x_i\)\(\sum (x_i - a) \geq 0\),那么这个平均数就可以达到。

    而判断能否选出这些数就是个简单dp,令\(g_i = x_i - a\),记\(f[i][0/1]\)表示第 \(i\)个数选或不选的最大值,\(f[i][0] = f[i - 1][1], f[i][1] = \min(f[i - 1][0], f[i - 1][1]) + g_i\),最后看\(\max(f[n][0], f[n][1])\)是否大于等于0即可。

    中位数的话也一样,即如果有一半的数小于等于中位数。即令\(g_i = [x_i >= a] * 2 - 1\),同样用上述 \(f\),最后看 \(\max(f[n][0], f[n][1])\)是否大于0即可。

    神奇的代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const double eps = 1e-5;
    
    int main(void) {
        ios::sync_with_stdio(false); 
        cin.tie(0); cout.tie(0);
        int n;
        cin >> n;
        vector<int> qwq;
        LL sum = 0;
        for(int i = 1; i <= n; ++ i){
            LL x;
            cin >> x;
            qwq.push_back(x);
            sum += x;
        }
        double l = 0, r = 1e9 + 7;
        auto check = [qwq](double x){
            vector<vector<double>> dp(qwq.size(), vector<double>(2, 0));
            dp[0][1] = qwq[0] - x;
            for(int i = 1; i < qwq.size(); ++ i){
                dp[i][0] = dp[i - 1][1];
                dp[i][1] = max(dp[i - 1][0], dp[i - 1][1]) + qwq[i] - x;
            }
            return dp.back()[0] >= 0 || dp.back()[1] >= 0;
        };
        while(l + eps < r){
            double mid = (l + r) / 2;
            if (check(mid))
                l = mid;
            else 
                r = mid;
        }
        cout << fixed << setprecision(8) << l << endl;
        auto check2 = [qwq](int x){
            vector<vector<int>> dp(qwq.size(), vector<int>(2, 0));
            dp[0][1] = (qwq[0] >= x) * 2 - 1;
            for(int i = 1; i < qwq.size(); ++ i){
                dp[i][0] = dp[i - 1][1];
                dp[i][1] = max(dp[i - 1][0], dp[i - 1][1]) + (qwq[i] >= x) * 2 - 1;
            }
            return dp.back()[0] > 0 || dp.back()[1] > 0;
        };
        int ll = 0, rr = 1e9 + 7;
        while(ll + 1 < rr){
            int mid = (ll + rr) >> 1;
            if (check2(mid))
                ll = mid;
            else 
                rr = mid;
        }
        cout << ll << endl;
        return 0;
    }
    


  • 相关阅读:
    Asp.net性能优化总结(一)
    Visual C#常用函数和方法集汇总
    ASP.net下大文件上传的解决方案及WebbUpload组件源码
    正则表达式学习
    在Asp.net中为图像加入版权信息
    Cognos 维度函数
    Cognos8.3函数使用手册(二)
    cognos更新步聚
    Cognos8.3函数使用手册(一)
    Cognos 8 报表备份和恢复
  • 原文地址:https://www.cnblogs.com/Lanly/p/15850248.html
Copyright © 2020-2023  润新知