题意:
合并果子升级版
可以一次合并 k 堆果子,给出体力上限 T,求最小的 K 使得耗费体力不超过 T
思路:
显然二分答案,然后扔到 priority_queue 里面,然后就 TLE 了
然后就去百度了
http://blog.csdn.net/libin66/article/details/52565484 这篇的思路写的不错
http://www.cnblogs.com/jhz033/p/5879452.html 这篇的代码写的不错
(好了,没我要说的话了)
原数组读进来排个序就可以冒充一个优先队列,
每次合并的结果因为本身就有递增的性质,所以扔到另开的另一个队列里,就必然是一个优先队列
然后两个队列每次取头出来比就像归并一样,就可以愉快的玩耍了
需要注意的是不整除时应该先将(余数+1)的部分取掉扔到第二个队列里,或者直接在前面补0假装有足够整除的果子
(智障如我第一次将它取出来后又填补到了原数组中WA了一晚上)
AC代码如下:
#include <cstdio>
#include <cctype>
#include <queue>
#include <cmath>
#include <algorithm>
#define maxn 100010
using namespace std;
typedef long long LL;
queue<LL> q1, q2;
LL n, t, a[maxn];
bool can(LL k) {
// printf("%d\n", k);
while (!q1.empty()) q1.pop();
while (!q2.empty()) q2.pop();
LL cost = 0;
LL x = (n - 1) % (k - 1);
if (x) {
for (int i = 0; i < k - 1 - x; ++i) q1.push(0);
}
for (LL i = 0; i < n; ++i) q1.push(a[i]);
LL times = ceil((double)(n - 1) / (k - 1));
for (LL i = 0; i < times; ++i) {
LL c0 = 0;
for (LL j = 0; j < k; ++j) {
if (!q1.empty() && !q2.empty()) {
LL u = q1.front(), v = q2.front();
if (u <= v) { c0 += (LL)u; q1.pop(); }
else { c0 += (LL)v; q2.pop(); }
}
else if (q1.empty()) {
c0 += (LL)q2.front(); q2.pop();
}
else { c0 += (LL)q1.front(); q1.pop(); }
if (c0 > t) return false;
}
q2.push(c0);
cost += c0;
// printf("%lld %lld\n", k, cost);
if (cost > t) return false;
}
// printf("%d %d\n", k, cost);
return true;
}
void work() {
scanf("%lld%lld", &n, &t);
for (LL i = 0; i < n; ++i) scanf("%lld", &a[i]);
sort(a, a + n);
LL lo = 2, hi = n;
while (hi > lo) {
LL mid = (hi + lo) >> 1;
if (can(mid)) hi = mid;
else lo = mid + 1;
}
printf("%lld\n", lo);
}
int main() {
freopen("5884.in", "r", stdin);
LL T;
scanf("%lld", &T);
while (T--) work();
return 0;
}