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;
}


posted @ 2022-01-27 16:22  ~Lanly~  阅读(147)  评论(0编辑  收藏  举报