这题真心比较奥义,先见这个人的博客:http://blog.csdn.net/libin66/article/details/52565484

  补0的方法是使得其满足成为满K叉树,而其博客中所说的“所以当(n-1)%(k-1)!=0的时候,会出现归并不能最大化个数的情况,这样会影响二分的单调性”我作如下的解释:

  至于为什么不加0,sum会变大呢?作如下的解释:因为有一次合并不是最大个数的话,与其让它在后面单独合并增加权值还不如在前面补0合并呢,毕竟我们在算k的时候sum越小越好嘛~

  原先代码如下(WA):

 #include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
using namespace std;
const int N = + ;
typedef long long ll; int n,lim;
int a[N]; bool can(int k)
{
if(k == ) return false;
queue<ll> Q1,Q2;
ll sum = ;
for(int i=;i<=n;i++) Q1.push((ll)a[i]);
while(Q1.size()+Q2.size() > )
{
if(Q1.size()+Q2.size() >= k)
{
ll temp = ;
for(int i=;i<=k;i++)
{
if(Q2.size()==)
{
temp += Q1.front();Q1.pop();
}
else if(Q1.size()==)
{
temp += Q2.front();Q2.pop();
}
else if(Q1.front()<=Q2.front())
{
temp += Q1.front();Q1.pop();
}
else
{
temp += Q2.front();Q2.pop();
}
}
sum += temp;
Q2.push(temp);
}
else
{
ll temp = ;
while(!Q1.empty())
{
temp += Q1.front();Q1.pop();
}
while(!Q2.empty())
{
temp += Q2.front();Q2.pop();
}
sum += temp;
}
}
return sum <= (ll)lim;
} int main()
{
int T;scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&lim);
for(int i=;i<=n;i++) scanf("%d",a+i);
sort(a+,a++n);
int L = , R = n;
int ans = ;
while(L <= R)
{
//printf("!! %d %d\n",L,R);
int mid = L + R >> ;
if(can(mid))
{
ans = mid;
R = mid - ;
}
else L = mid + ;
}
printf("%d\n",ans);
}
return ;
} /*
6
6 120
10 10 10 10 10
*/

WA的代码

  AC代码如下:

 #include<iostream>
//#include<bits/stdc++.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<ctime>
#include<algorithm>
#include<cmath>
#include<vector>
#define showtime fprintf(stderr,"time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
typedef long long LL;
#define MP make_pair
#define PII pair<int,int>
#define PLI pair<long long ,int>
#define PFI pair<double,int>
#define PLL pair<ll,ll>
#define PB push_back
#define F first
#define S second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define debug cout<<"?????"<<endl;
//freopen("1005.in","r",stdin);
//freopen("data.out","w",stdout);
const int INF = 0x7f7f7f7f;
const double eps = 1e-;
const int M = + ;
const int N = + ;
const double PI = acos(-.);
const double E = 2.71828182845904523536;
const int MOD = ;
typedef vector<ll> Vec;
typedef vector<Vec> Mat;
int T,n,a[ + ];
ll m;
bool ok(int k){
queue<ll> q,p;
int t = (n-) % (k-);
// 每次减少k-1个数。一共要减少 (n-1) 个数。 还剩下几个数要和 0 一组了
if(t != ) for(int i = ; i < k - t - ; i ++) q.push();
for(int i = ; i < n ; i ++) q.push(a[i]); ll ans = ;
while(!q.empty() || !p.empty()){
ll tmp = ;
for(int i = ; i < k ; i ++){
if(!q.empty() && !p.empty()){
ll u = q.front() , v = p.front();
if(u < v) tmp += u , q.pop();
else tmp += v , p.pop();
}else if(!q.empty()){
ll u = q.front(); q.pop();
tmp += u;
}else if(!p.empty()){
ll v = p.front() ; p.pop();
tmp += v;
}else break;
}
ans += tmp;
if(q.empty() && p.empty()) break;
p.push(tmp);
}
return ans <= m;
}
void solve(){
int l = , r = n;
while(l < r){
int m = (l+r)>>;
if(ok(m)) r = m;
else l = m + ;
}
cout << l << endl;
}
int main(){
cin >> T;
while(T --){
cin >> n >> m;
for(int i = ; i < n ; i ++) scanf("%d",&a[i]);
sort(a,a+n);
solve();
}
return ;
}

AC代码

HDU 5884 Sort ——(K叉哈夫曼树)的更多相关文章

  1. 两个队列+k叉哈夫曼树 HDU 5884

    // 两个队列+k叉哈夫曼树 HDU 5884 // camp题解: // 题意:nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, ...

  2. 2016 年青岛网络赛---Sort(k叉哈夫曼)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5884 Problem Description Recently, Bob has just learn ...

  3. hdu5884 Sort(二分+k叉哈夫曼树)

    题目链接:hdu5884 Sort 题意:n个有序序列的归并排序.每次可以选择不超过k个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问k最小是多少. 题解:先二分k,然后在k给 ...

  4. 【CF884D】Boxes And Balls k叉哈夫曼树

    题目大意:给定一个大小为 N 的集合,每次可以从中挑出 2 个或 3 个数进行合并,合并的代价是几个数的权值和,求将这些数合并成 1 个的最小代价是多少. 引理:K 叉哈夫曼树需要保证 \((n-1) ...

  5. UOJ#130 【NOI2015】荷马史诗 K叉哈夫曼树

    [NOI2015]荷马史诗 链接:http://uoj.ac/problem/130 因为不能有前缀关系,所以单词均为叶子节点,就是K叉哈夫曼树.第一问直接求解,第二问即第二关键字为树的高度. #in ...

  6. AcWing:149. 荷马史诗(哈夫曼编码 + k叉哈夫曼树)

    追逐影子的人,自己就是影子. ——荷马 达达最近迷上了文学. 她喜欢在一个慵懒的午后,细细地品上一杯卡布奇诺,静静地阅读她爱不释手的<荷马史诗>. 但是由<奥德赛>和<伊 ...

  7. HDU 5884 Sort (二分+k叉哈夫曼树)

    题意:n 个有序序列的归并排序.每次可以选择不超过 k 个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问 k最小是多少. 析:首先二分一下这个 k .然后在给定 k 的情况下, ...

  8. bzoj 4198 [ Noi 2015 ] 荷马史诗 —— 哈夫曼编码(k叉哈夫曼树)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4198 第一次写哈夫曼树!看了很多博客. 哈夫曼树 & 哈夫曼编码:https://w ...

  9. P2168 [NOI2015]荷马史诗 k叉哈夫曼树

    思路:哈夫曼编码 提交:1次(参考题解) 题解:类似合并果子$QwQ$ 取出前$k$小(注意如果叶子结点不满的话要补全),合并起来再扔回堆里去. #include<cstdio> #inc ...

  10. BZOJ 4198: [Noi2015]荷马史诗 哈夫曼树 k叉哈夫曼树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4198 https://blog.csdn.net/chn_jz/article/details/7 ...

随机推荐

  1. 查询进程内存,cpu占用情况。僵尸进程

    查使用内存最多的5个进程:ps aux | head -1 && ps aux | grep -v USER | sort -nr -k 4 | head -5 查使用CPU最多的5个 ...

  2. ns nat rule

    ns nat rule NAT实现方式: NAT的实现方式有三种,即静态转换(Static Nat).动态转换(Dynamic Nat) 和 端口多路复用(OverLoad). 静态转换是指将内部网络 ...

  3. JavaSE基础知识之继承

    一.概述 继承描述的是事物之间的所属关系,这种关系是: is-a 的关系.例如,图中的兔子属于食草动物,食草动物又属于动物.继承可以使多种事物之间形成一种关系体系,让父类更通用,子类更具体. 1.1  ...

  4. C语言无法使用引用,一定要使用怎么办? ------指针的指针做参数

    #include <stdio.h> #include <stdlib.h> #include <string.h> void fun1(char** s); vo ...

  5. 简单了解soap协议

    SOAP的是什么的简写 soap是(Simple Object Access Protocal)的简写,即简单对象访问协议,它描述了一种在分散或分布式的环境中如何交换信息的轻量级协议. soap用来干 ...

  6. 爱上Java诊断利器之Arthas

    1. Arthas是什么? 摘自Arthas的Github介绍: Arthas is a Java Diagnostic tool open sourced by Alibaba. Arthas al ...

  7. Invalid prop: custom validator check failed for prop "pagerCount"

    在element分页中使用pager-count报错: vue.esm.js?c5de:628 [Vue warn]: Invalid prop: custom validator check fai ...

  8. mybatis sql语句中 in() 长度为0或null的情况

    mybatis sql语句中 in() 长度为0或null的情况 比如: select * from A where colName IN <foreach collection="m ...

  9. docker 卸载旧版本

    列出docker安装过的相关包: sudo yum list installed | grep docker 删除相关安装包 sudo yum -y remove docker-ce.x86_64su ...

  10. ActiveMQ基础简介

    1. 什么是ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现 ...