atc-E - Average and Median

题意:

n个数字,每次可以选择第i个或者第i+1个,问选择的序列的最大平均值和最大中位数;

思路:

二分最值,使用动态规划来判断

代码:

#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'

const int N = 200010;
double f[N][2];
double a[N];
int n;
bool check(double mid) {
    for (int i = 1; i <= n; i++) f[i][1] = f[i][0] = -1;
    vector<double> b(n + 1);
    for (int i = 1; i <= n; i++) {
        b[i] = a[i] - mid;//判断平均数常用技巧,给每个数字减去mid,求和之后大于0说明平均值大于mid
    }
    f[0][0] = 0;
    f[0][1] = 0;
    for (int i = 1; i <= n; i++) {
        f[i][0] = f[i - 1][1];
        f[i][1] = max(f[i - 1][0], f[i - 1][1]) + b[i];
    }
    return max(f[n][1], f[n][0]) >= 0.0;
}
bool check1(int mid) {
    vector<int> s(n + 1);
    for (int i = 1; i <= n; i++) {
        if (a[i] >= mid) s[i] = 1;
        else s[i] = -1;//选择n个数字,若mid为中位数,则至少有n/2+1个数字大于等于mid,所以只需要判断和是否大于0即可
    }
    for (int i = 1; i <= n; i++) f[i][1] = f[i][0] = -1;
    f[0][0] = 0;
    f[0][1] = 0;
    for (int i = 1; i <= n; i++) {
        f[i][1] = max(f[i - 1][1], f[i - 1][0]) + s[i];
        f[i][0] = f[i - 1][1] ;
    }
    return max(f[n][1], f[n][0]) > 0;

}
void solve(int Case) {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    double l = 0, r = 1e9 + 10;
    while (r - l > 1e-6) {
        double mid = (l + r) / 2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    cout << l << nline;
    int ll = 0, rr = 1e9 + 10;
    while (ll < rr) {
        int mid = ll + rr + 1 >> 1;
        if (check1(mid)) ll = mid;
        else rr = mid - 1;
    }
    cout << ll << nline;

}

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
//   cin >> _; for (Case = 1; Case <= _; Case++)
    solve(Case);

    return 0;
}
posted @ 2022-03-14 17:13  指引盗寇入太行  阅读(51)  评论(0编辑  收藏  举报