可以把每堆糖果抽象成一个集合
每次从两个集合各取一个元素,问最后能否把所有集合取完
感觉这个题还是比较简单的
读完之后就想着用优先队列来做
每次找到两个最大的集合,保证把较小集合元素取完
一直这样做下去直到所有集合都空或剩余一个元素个数大于1的集合
421ms代码如下:
#include <queue>
#include <cstdio>
using namespace std;
bool ok;
int T, n, x, y, tmp;
priority_queue<int, vector<int>, less<int> > q;
int main(void) {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
ok = false;
while(n--) {
scanf("%d", &x);
q.push(x);
}
while(true) {
if(!q.empty()) {
x = q.top();
q.pop();
} else {
ok = true;
break;
}
if(!q.empty()) {
y = q.top();
q.pop();
} else if(x > 1) {
ok = false;
break;
} else {
ok = true;
break;
}
//printf("x = %d\ty = %d\n", x, y);
tmp = min(x, y);
x -= tmp;
y -= tmp;
if(x > 0) q.push(x);
if(y > 0) q.push(y);
}
if(ok) printf("Yes\n");
else printf("No\n");
}
}
后来看了评论里发现了一个很犀利的做法
判断集合个数总和sum与最大集合个数maxv之间的关系
如果sum+1 >= 2*maxv 则yes
否则no
想了下觉得可以这样证明:
如果把所有的集合分成两个集合maxv sum-maxv
那么很容易想到结果为yes的情况正好对应于abs(s1-s2) <= 1
否则为no
贴上别人的证明:
证明:
1.把某种糖果看做隔板,如果某种糖果有n个,那么就有n+1块区域,至少需要n-1块其他种糖果才
能使得所有隔板不挨在一块..也就是说能吃完这种糖果.至少需要其他种类糖果n-1块..(鸽巢原理)
2.数量最多的糖果(隔板)可以构造最多的空间,如果这种糖果有maxn个....那么需要maxn-1个其
他种糖果.对于某种数量少于maxn的糖果来说,可以在原本数量最多的糖果构造的隔板上"加厚"原
有的隔板...,那么这"某种糖果"就销声匿迹了.....
考虑极端情况.如果某种糖果无法在这maxn+1的空间内构造出符合条件的序列,那么这种糖果至
少要有maxn+1+1个(考虑只有两种糖果的情况)...(鸽巢原理)...但是这与数量最多的那种糖果只有
maxn个矛盾.....(maxn+1+1>maxn 这不等式不难理解吧....).
想一下是不是这样?
那么下面代码里为什么要使maxv取所有集合元素个数的最大值呢?
156ms代码如下:
#include <stdio.h>
#define LL long long
int T, n, a, maxv;
LL sum;
int main(void) {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
sum = 0ll;
maxv = -1;
while(n--) {
scanf("%d", &a);
sum += a;
maxv = maxv > a ? maxv : a;
}
sum -= maxv;
if(sum >= maxv-1) printf("Yes\n");
else printf("No\n");
}
return 0;
}