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. kvc to nsdata

        [NSKeyedArchiver archivedDataWithRootObject:arr];    [NSKeyedUnarchiver unarchiveObjectWithData: ...

  2. ActiveAndroid问题no such table解决总结

     android.database.sqlite.SQLiteException: no such table  at android.database.sqlite.SQLiteConnection ...

  3. 使用Google Colab训练神经网络(二)

    Colaboratory 是一个 Google 研究项目,旨在帮助传播机器学习培训和研究成果.它是一个 Jupyter 笔记本环境,不需要进行任何设置就可以使用,并且完全在云端运行.Colaborat ...

  4. jquery插件serializeFormToObject

    $.fn.serializeObject = function() { var o = {}; var a = this.serializeArray(); $.each(a, function() ...

  5. 数据库_7_SQL基本操作——表操作

    SQL基本操作——表操作 建表的过程就是声明列的过程. 表与字段是密不可分的. 一.新增数据表 create table [if not exists] 表名( 字段名字 数据类型, 字段名字 数据类 ...

  6. Day5 集合的深浅copy

    集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 去重,把一个列表变成集合,就自动去重了. 关系测试, ...

  7. ccf_201712-2

    题目 问题描述 有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向. 游戏开始,从1 ...

  8. Web鼠标事件

    mousedown:鼠标按下 mouseup:鼠标抬起 mousemove:鼠标移动 mouseout:在父元素上绑定该事件,当鼠标从父元素或者从子元素上离开时都会触发该事件 mouseleave:和 ...

  9. 条款40:明智而审慎地使用多重继承(use multiple inheritance judiciously)

    NOTE: 1.多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. 2.virtual 继承会增加大小 速度 初始化(及赋值)复杂度等等成本.如果virtual base ...

  10. 【java】抽象类继承关系

    抽象类: 抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充. 一个类不能同时被 abstract 和 final 修饰.如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将 ...