http://acm.hdu.edu.cn/showproblem.php?pid=5884

参考:https://www.cnblogs.com/jhz033/p/5879452.html

【题意】

n个有序序列的归并排序.每次可以选择不超过k个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问k最小是多少。

【思路】

k越大,代价越小,二分k,check k

对于每个k,问题转化为n个结点的最优k叉树,用堆做时间复杂度为O(nlogn),再加上二分总复杂度是O(nlogn^2)

然后T了。。。听说加输入挂可以卡过去

正解是这样的:

原数组排序,预处理时间复杂度O(nlogn)

然后求最优k叉树,用一个队列维护合并后的值,而不需要加入原来的堆里重排序(利用新加入的内结点本身的单调性),每次时间复杂度为O(n)

O(nlogn)+O(logn)*O(n),所以最后时间复杂度是O(nlogn)

n个结点不一定能构成最优k叉树,需要补 k-1-((n-1)%(k-1))个权为0的虚结点。

 #include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
int n;
ll t;
const int maxn=1e5+;
ll a[maxn];
bool judge(int mid){
int cnt=(n-)/(mid-);
queue<ll> Q;
if((n-)%(mid-)!=){
cnt++;
for(int i=;i<(mid--(n-)%(mid-));i++){
Q.push();
}
}
ll ans=;
int l=;
while(cnt--){
ll tmp=;
for(int i=;i<mid;i++){
if(!Q.empty()&&(l>=n||Q.front()<=a[l])){
tmp+=Q.front();
Q.pop();
}else{
tmp+=a[l++];
}
}
ans+=tmp;
Q.push(tmp);
}
if(ans<=t) return true;
return false;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%lld",&n,&t);
for(int i=;i<n;i++){
scanf("%lld",&a[i]);
}
sort(a,a+n);
int l=,r=n;
while(l<=r){
int mid=(l+r)>>;
if(judge(mid)){
r=mid-;
}else{
l=mid+;
}
}
printf("%d\n",l);
}
return ;
}
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef long long ll;
int n;
ll t;
const int maxn=1e5+;
ll a[maxn];
bool judge(int mid){
queue<ll> Q1,Q2;
for(int i=;i<n;i++) Q1.push(a[i]);
if((n-)%(mid-)!=){
for(int i=;i<(mid--(n-)%(mid-));i++){
Q2.push();
}
}
ll ans=;
while(Q1.size()+Q2.size()>=mid){
ll tmp=;
for(int i=;i<mid;i++){
if(Q1.empty()&&!Q2.empty()){
tmp+=Q2.front();
Q2.pop();
}else if(Q2.empty()&&!Q1.empty()){
tmp+=Q1.front();
Q1.pop();
}else if(!Q1.empty()&&!Q2.empty()){
if(Q1.front()<=Q2.front()){
tmp+=Q1.front();
Q1.pop();
}else{
tmp+=Q2.front();
Q2.pop();
}
}
}
// cout<<tmp<<endl;
ans+=tmp;
Q2.push(tmp);
}
if(ans<=t) return true;
return false;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%lld",&n,&t);
for(int i=;i<n;i++){
scanf("%lld",&a[i]);
}
sort(a,a+n);
int l=,r=n;
while(l<=r){
int mid=(l+r)>>;
if(judge(mid)){
r=mid-;
}else{
l=mid+;
}
}
printf("%d\n",l);
}
return ;
}

【最优K叉树】hdu 5884 Sort的更多相关文章

  1. HDU 5884 Sort ——(K叉哈夫曼树)

    这题真心比较奥义,先见这个人的博客:http://blog.csdn.net/libin66/article/details/52565484 补0的方法是使得其满足成为满K叉树,而其博客中所说的“所 ...

  2. HDU 5884 Sort(二分答案+计算WPL的技巧)

    Sort Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

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

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

  4. HDU 5884 Sort (二分)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5884 nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的 ...

  5. HDU 5884 Sort(二分+优先队列)

    http://acm.hdu.edu.cn/showproblem.php?pid=5884 题意:有个屌丝设计了一个程序,每次可以将k个数组进行合并,代价为这k个数组总的长度之和.现在另外一个屌丝要 ...

  6. HDU 5884 Sort

    二分,验证. 二分$k$,然后进行验证.有一个地方需要注意一下:如果$n$个数,每次合并$k$个,最后一次不能合$k$个,那么一开始需要补$0$之后再合并才是最优的.合并的时候用优先队列合并时间复杂度 ...

  7. HDU 5884 Sort(2016年青岛网络赛 G 二分+贪心+小优化)

    好题 题意:给你n<=100000个数,每个数范围[0,1000],然后给你一个最大的代价T,每次最多合并k个数成为一个数,代价为k个数的总和.问最后合成1个数的总代价不大于T的最小k 题解:我 ...

  8. HDU - 5884 Sort (二分答案+贪心)

    有n个数字,你需要把这n个数字合成一个数字,每次只能把k个数字合并成一个,花费为这k个数字的和. 给一个最大花费,问不超过这个最大花费的情况下,k的最小值. Sample Input 1 5 25 1 ...

  9. 贪心(哈夫曼树):HDU 5884 sort

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA2QAAAKACAIAAAB8KCy/AAAgAElEQVR4nOy9a5Adx3UmWL+kHxuekU ...

随机推荐

  1. 修改本地dns域名对应的 ip

    C:\Windows\System32\drivers\etc 打开 hosts 文件 在浏览器 访问 http://a.com,就相当于访问 127.0.0.2 这个ip了

  2. python 基础网络编程2

    python 基础网络编程2 前一篇讲了socketserver.py中BaseServer类, 下面介绍下TCPServer和UDPServer class TCPServer(BaseServer ...

  3. Android(java)学习笔记144:网络图片浏览器的实现(ANR)

    1.我们在Android下,实现使用http协议进行网络通信,请求网络数据.这里是获取网络上的图片信息,让它可以显示在手机上: 但是我们这个手机连接网络是很费时间,如果我们在主线程(UI线程)中写这个 ...

  4. build.sbt的定义格式

    一个简单的build.sbt文件内容如下: name := "hello" // 项目名称 organization := "xxx.xxx.xxx" // 组 ...

  5. iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select

    iview 验证 trigger: 'blur,change', 同时加两个,省的每次还想input 还是 select dataRuleValidate: { name: [{ required: ...

  6. 用函数创建对象、类创建对象,以及使用prototype的好处

    用函数创建对象 var CheckObject = function(){}; CheckObject.checkName = function(){ // 检验姓名 }; CheckObject.c ...

  7. UEditor练习(JSP版)

    下载1.4.3.3jsp版本的源码. <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  8. Encryption-基础:base64加解密

    环境:vc2003 .h /********** This library is free software; you can redistribute it and/or modify it und ...

  9. 解析IPV4报文 和IPV6 报文的 checksum

    解析IPV4报文和IPV6报文的checksum的算法: 校验和(checksum)算法,简单的说就是16位累加的反码运算: 计算函数如下: 我们在计算时是主机字节序,计算的结果封装成IP包时是网络字 ...

  10. redis集群理解

    Redis在3.0中也引入了集群的概念,用于解决一些大数据量和高可用的问题,但是,为了达到高性能的目的,集群不是强一致性的,使用的是异步复制,在数据到主节点后,主节点返回成功,数据被异步地复制给从节点 ...