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

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

题意:
有个屌丝设计了一个程序,每次可以将k个数组进行合并,代价为这k个数组总的长度之和。现在另外一个屌丝要他最后合并成一个数组时的总代价不能超过T。求k的最小值。

思路:
贪心策略是长度越小的肯定先进行合并。一开始是直接用一个优先队列,但是这样会TLE的。。

后来改成了用两个队列进行模拟,先将数组排好序然后放入队列之中,每次合并之后的放入另一个队列之中,每次只需要再两个队列之中选择小的即可。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 #include<set>
11 #include<bitset>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,int> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn=100000+5;
17
18 ll n,t;
19 int a[maxn];
20
21 bool solve(int x)
22 {
23     queue<ll> q1,q2;
24     int left=(n-1)%(x-1);
25     if(left) for(int i=1;i<=x-1-left;i++)  q1.push(0);
26     for(int i=1;i<=n;i++)  q1.push(a[i]);
27     ll sum=0;
28
29     while(!q1.empty() || !q2.empty())
30     {
31         int tmp=0;
32         for(int i=1;i<=x;i++)
33         {
34             if(q1.empty())
35             {
36                 tmp+=q2.front();
37                 q2.pop();
38             }
39             else if(q2.empty())
40             {
41                 tmp+=q1.front();
42                 q1.pop();
43             }
44             else
45             {
46                 int u=q1.front();
47                 int v=q2.front();
48                 if(u<v)
49                 {
50                     tmp+=u;
51                     q1.pop();
52                 }
53                 else
54                 {
55                     tmp+=v;
56                     q2.pop();
57                 }
58             }
59         }
60         sum+=tmp;
61         if(!q1.empty() || !q2.empty())  q2.push(tmp);
62     }
63     return sum<=t;
64 }
65
66 int main()
67 {
68     //freopen("in.txt","r",stdin);
69     int T;
70     scanf("%d",&T);
71     while(T--)
72     {
73         scanf("%lld%lld",&n,&t);
74         for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
75         sort(a+1,a+n+1);
76         int ans=1;
77         int l=2,r=n;
78         while(l<=r)
79         {
80             int mid=(l+r)/2;
81             if(solve(mid)) {ans=mid;r=mid-1;}
82             else l=mid+1;
83         }
84         printf("%d\n",ans);
85     }
86     return 0;
87 }
时间: 2024-08-28 07:55:24

HDU 5884 Sort(二分+优先队列)的相关文章

HDU 5884 Sort (二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5884 nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, 问kk最小是多少 用一个队列维护合并的数,二分一下判断合理性.注意一点的是要是(n - 1)%(k - 1) != 0的话,就要先合并前(n - 1)%(k - 1) + 1项,这样会更优一点.还有细节问题很多要注意. 1 //#pragma comment(linker,

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

题意:n 个有序序列的归并排序.每次可以选择不超过 k 个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T, 问 k最小是多少. 析:首先二分一下这个 k .然后在给定 k 的情况下,这个代价其实就是 k 叉的哈夫曼树问题.然后用两个队列维护一下就好. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string>

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

有n个数字,你需要把这n个数字合成一个数字,每次只能把k个数字合并成一个,花费为这k个数字的和. 给一个最大花费,问不超过这个最大花费的情况下,k的最小值. Sample Input 1 5 25 1 2 3 4 5 Sample Output 3 这个题很容易想到二分答案+优先队列check 然而这样复杂度是 O(n logn*logn ),会TLE(这特么都会TLE?加个读入优化就过了) 可以先给所有数字排个序,然后用两个队列,一个存原来的数字,一个存新合成的数字. 所以两个队列都是有序的.

HDU - 5884 - Sort

原题链接 题意 给你n个序列以及序列内元素个数,现要求进行归并,花费为归并过程中序列长度的和,给定一个花费T,问最小的k(每次归并的最大序列个数)为多少. 分析 首先应该想到的是二分.然后思考如何check呢.排序,贪心的来,每次都选最小的前若干个.要注意的是,最后k-1个当然是在最后一次归并,那么要满足这样的情况,我们要判断(n-1)%(k-1)是否有剩余,有的话就先进行一次[余数+1]的归并,这样就保持了最优. #include <iostream> #include<cstdio&

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

这题真心比较奥义,先见这个人的博客:http://blog.csdn.net/libin66/article/details/52565484 补0的方法是使得其满足成为满K叉树,而其博客中所说的“所以当(n-1)%(k-1)!=0的时候,会出现归并不能最大化个数的情况,这样会影响二分的单调性”我作如下的解释: 至于为什么不加0,sum会变大呢?作如下的解释:因为有一次合并不是最大个数的话,与其让它在后面单独合并增加权值还不如在前面补0合并呢,毕竟我们在算k的时候sum越小越好嘛~ 原先代码如下

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

这道题目,我做的时候不会哈夫曼树,自己贪心是错的都不知晓.还可以发现这里不必用优先队列,可以用两个队列,毕竟插入的数是有单调性的. 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 using namespace std; 6 const int N=300010; 7 int a[N],n,S,f1,f2,b1,b2; 8 int

HDU 5884 Sort -2016 ICPC 青岛赛区网络赛

题目链接 #include <iostream> #include <math.h> #include <stdio.h> #include<algorithm> #include<cstring> #include<queue> using namespace std; int data[100005]; int main() { int T,n,t; scanf("%d",&T); while(T--)

Hdu 5884

hdu 5884 Sort 题意: n个有序序列的归并排序.每次可以选择不超过k个序列进行合并,合并代价为这些序列的长度和,总的合并代价不能超过T, 问k最小是多少. 解法: 1:首先想到的是二分这个答案k,然后check每个k是否可行 2:对于每个k,总共需要归并n-1个数,每次归并k-1个数 所以当(n-1)%(k-1)!=0的时候,会出现归并不能最大化个数的情况,这样会影响二分的单调性 我们先取(n-1)%(k-1)个小的数凑成一次k,接下来的数我们已经知道了肯定是(n-1)/(k-1)块

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

1 // 两个队列+k叉哈夫曼树 HDU 5884 2 // camp题解: 3 // 题意:nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, 问kk最小是多少. 4 // . 5 // 题解:首先二分一下这个kk.然后在给定kk的情况下,这个代价其实就是kk叉的哈夫曼树问题.因此直接套用哈夫曼树的堆做法即可.复杂度O(nlog^2n) 6 // ?,这样优化一下读入是可以卡过去的. 7 // 然后主代码手表示,利用合并的单调