您的位置:首页 > 其它

hdu 5884 Sort 二分 + K叉哈夫曼树 两个队列

2017-07-28 23:56 459 查看
题目链接

题意:

合并果子升级版

可以一次合并 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
d773
, 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: