题目描述
难度分:2500
输入T表示T组数据。所有数据的n之和≤105。
每组数据输入n(1≤n≤105)表示有2n−1个盒子。
然后输入2n−1行,每行2个数字a[i]和o[i],表示第i个盒子中的苹果个数和橘子个数,元素范围[0,109]。
你需要从这2n−1个盒子中,选出n个盒子。能否使这n个盒子中的苹果个数之和≥Σ2n−1i=1a[i]2,且橘子个数之≥Σ2n−1i=1o[i]2?
如果不能,输出NO
,否则输出YES
和你选的这n个盒子的编号(按照输入的顺序,编号从1开始)。
输入样例
2
2
10 15
5 7
20 18
1
0 0
输出样例
YES
1 3
YES
1
算法
数学
这个题的感觉就是从哪个数学竞赛挖过来的,对a升序排列,那么以下两种方案必然有一种是可以的:
- 选择a1,a3,…,a2n−5,a2n−3,a2n−1。
- 选择a2,a4,…,a2n−4,a2n−2,a2n−1。
如果是方案一,由于a2k+1≥a2k,k∈N∗成立,再算上a1,方案一的总苹果数一定不会少于总数的一半。
如果是方案二,由于a2k≥a2k−1,k∈N∗,再算上a2n−1,方案二的总苹果数一定不会少于总数的一半。
此时我们就只需要证明这两种方案对应的橘子总数不可能都少于橘子总数的一半即可。设橘子总数为s,且满足以下两个不等关系:
- s1=o1+o3+…+o2n−5+o2n−3+o2n−1<s2
- s2=o2+o4+…+o2n−4+o2n−2+o2n−1<s2。
那么就有s1+s2+2o2n−1<s,而s=s1+s2+o2n−1,这就会推出o2n−1<0,矛盾。所以本题一定有解,我们只需要检查一下两种方案哪种可以,然后输出那个可以的方案就行。
复杂度分析
时间复杂度
排序之后的判断是O(n)的,只需要遍历数组,因此算法的性能瓶颈在于排序,时间复杂度为O(nlog2n)。
空间复杂度
除了输入的a数组和o数组,仅使用了有限几个变量,因此空间瓶颈也在于排序,快排的额外空间复杂度为O(log2n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 200010;
int T, n;
LL tot_a, tot_o;
struct Box {
int i, a, o;
bool operator<(const Box other) const {
return a < other.a;
}
} boxes[N];
bool solve(int tp) {
LL sum_o = boxes[2*n - 1].o;
for(int i = tp; i < 2*n - 1; i += 2) {
sum_o += boxes[i].o;
}
return 2*sum_o >= tot_o;
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
tot_a = tot_o = 0;
for(int i = 1; i <= 2*n - 1; i++) {
scanf("%d%d", &boxes[i].a, &boxes[i].o);
boxes[i].i = i;
tot_a += boxes[i].a;
tot_o += boxes[i].o;
}
sort(boxes + 1, boxes + 2*n);
puts("YES");
if(solve(1)) {
for(int i = 1; i <= 2*n - 1; i += 2) {
printf("%d ", boxes[i].i);
}
puts("");
}else {
for(int i = 2; i <= 2*n - 1; i += 2) {
printf("%d ", boxes[i].i);
}
printf("%d\n", boxes[2*n - 1].i);
}
}
return 0;
}