CF 798D Mike and distribution - 贪心、思维

CF 798D Mike and distribution

题目链接:洛谷 CF 798D Mike and distribution CF 798D Mike and distribution

算法标签: 贪心思维

题目描述:

给两个长度为 \(n\) 的数列\(A,B\),要求至多选择 $\lfloor \frac{n}{2} \rfloor+1 $ 个下标,使得 \(A\) 数组中选出的数的和的两倍大于 \(sumA\) , \(B\) 数组中选出的数的和的两倍大于 \(sumB\)

题解:

贪心 + 思维!!!!

模拟赛T1,三个小时没有搞出正解 [擦汗.jpg]

既然题目中让我们最多选择 \(\lfloor \frac{n}{2} \rfloor+1\) ,并且没有要求最小,那么不妨我们就取 \(\lfloor \frac{n}{2} \rfloor+1\) 个值,显然这是对的(不要白不要啊……)。

之后我们考虑假如只有一个数列,这道题就变得很简单,排序之后找出前 \(\lfloor \frac{n}{2} \rfloor+1\) 个再判一下就可以。

那么对于两个数列怎么办???

现在我们来考虑这个神奇的 \(\lfloor \frac{n}{2} \rfloor+1\) ,本着给你就不白给的原则,我们会发现,这是什么

​ —— 两两分组再加一个

虽然很奇妙且扯皮淡雅,但是这的确是真的啊(考场上怎么可能 \(yy\) 出来???)

又因为排序可以处理两个数列中的一个,那么两两分组就可以处理第二个。 [肯定.jpg]


用结构体 \(node[~].a, node[~].b, node[~].id\) 存下来 \(A,B\) 数组和当前这对数在初始数列的位置。

首先按照数列\(A\)从大到小给结构体排序,我们就得到了一个 \(node[1].a \ge node[2].a \ge node[3].a \dots \ge node[n].a\) 的有序结构体,这样我们保证前 \(\lfloor \frac{n}{2} \rfloor+1\) 个\(A\)之和一定比剩下的\(A\)之和大。

之后我们假设先选择 \(node[1]\),之后对于后边的每一对值(两个值),选择其中 \(B\) 更大的一个,即对于\(node[2].b\),\(node[3].b\),选出更大的一个;对于 \(node[4].b,node[5].b\) ,选出更大的一个……

这时反观 \(A\) 的正确性,由于我们会发现 \(node[1].a \ge max(node[2].a, node[3].a),min(node[2].a, node[3].a) \ge max(node[4].a, node[5].a) \dots\)

所以现在 \(A\) 的正确性也是可以保证的。

之后就可以愉快的码代码了 !!! [开心.jpg]

AC代码

#include <bits/stdc++.h>

using namespace std;

#define setI(x) freopen(x".in", "r", stdin); 
#define setO(x) freopen(x".out", "w", stdout); 
#define setIO(x) setI(x) setO(x)

char *p1, *p2, buf[100000];

typedef long long ll;

#define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )

ll rd() {
    ll x = 0, f = 1;
    char c = nc();
    while (c < 48) { 
        if (c == '-') { 
            f = -1;
        }
        c = nc();
    }
    while (c > 47) {
        x = (((x << 2) + x) << 1) + (c ^ 48);
        c = nc();
    }
    return x * f;
}

const int N = 100010;

typedef long long ll;

struct Node {
    ll a, b;
    int id;
} node[N];

bool cmp(Node A, Node B) {
    if (A.a == B.a) {
        return A.b > B.b;
    }
    return A.a > B.a;
}

int n;

int main() {
    // setIO("game")
    n = rd();
    for (int i = 1; i <= n; i ++ ) {
        node[i].a = rd();
        node[i].id = i;
    }
    for (int i = 1; i <= n; i ++ ) {
        node[i].b = rd();
    }
    sort(node + 1, node + 1 + n, cmp);
    printf("%d\n", (n / 2) + 1);
    printf("%d ", node[1].id);
    for (int i = 2; i <= n; i += 2) {
        ll nowb = node[i].b;
        ll nxtb = node[i + 1].b;
        if (nowb > nxtb) {
            printf("%d ", node[i].id);
        }
        else {
            printf("%d ", node[i + 1].id);
        }
    }
    return 0;
}
上一篇:莫比乌斯反演[学习笔记]


下一篇:数据中台:前台调用能快速响应、数据口径一致(2)