Mike and distribution

题意:

给定 $n$ 个物品,每个物品有两个属性$a_i$, $b_i$,求一个长度为$[frac{n}{2}]+1$的子序列 $p$ 使得

$2 * sum_{i = 1}^{|p|}{a_{p_i}} > sum_{i=1}^n {a_i}$

$2 * sum_{i = 1}^{|p|}{b_{p_i}} > sum_{i=1}^n {b_i}$

解法:

非常巧妙的构造方法。

注意到题目的要求可以转化为非 $p_i$ 的集合的元素之和小于 $p_i$内元素之和。

考虑一种构造方法:

  首先按照$a_i$大小将物品从大到小进行排序。

  首先选上第一个物品,接下来对于后面的物品分成 $[frac{n-1}{2}]$ 个两对物品来看,

    对于每一对物品选取$b_i$较大的物品加入$p$集合。

  如果余下了一个物品,则加入$p$集合。

正确性:

  首先对于$b$,显然有原题要求条件成立。

  对于$a$,可以发现 $a_1$ 大于后面所有 $a_{i+1} - a_i$ 的和,这样,也成立。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define N 100010

using namespace std;

int n;
int a[N], p[N], b[N], c[N];

bool cmp(int x, int y)
{
    return a[x] > a[y];
}

int main()
{
    scanf("%d", &n);
    for(int i = 1;i <= n;i++) scanf("%d", &a[i]);
    for(int i = 1;i <= n;i++) scanf("%d", &b[i]);
    for(int i = 1;i <= n;i++) c[i] = i;
    sort(c + 1, c + n + 1, cmp);
    int tot = 0;
    p[tot = 1] = c[1];
    for(int i = 2;i <= n;i += 2)
    {
        if(i<n && b[ c[i] ] < b[ c[i+1] ]) p[++tot] = c[i+1];
        else p[++tot] = c[i];
    }
    sort(p + 1, p + tot + 1);
    cout << tot << endl;
    for(int i = 1;i <= tot;i++) cout << p[i] << ' ';
    cout << endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lawyer/p/6776972.html