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