首页 > 技术文章 > 两个队列+k叉哈夫曼树 HDU 5884

ITUPC 2016-09-18 10:51 原文

 1 // 两个队列+k叉哈夫曼树 HDU 5884
 2 // camp题解:
 3 // 题意:nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, 问kk最小是多少。
 4 // .
 5 // 题解:首先二分一下这个kk。然后在给定kk的情况下,这个代价其实就是kk叉的哈夫曼树问题。因此直接套用哈夫曼树的堆做法即可。复杂度O(nlog^2n)
 6 // ​,这样优化一下读入是可以卡过去的。
 7 // 然后主代码手表示,利用合并的单调性,可以去掉优先队列得到O(nlogn)的做法:先对所有数排序,另外一个队列维护合并后的值,取值时从两个序列前端取小的即可。
 8 // 昂:如果(n-1)%(k-1)≠0,要把最小的(n-1)%(k-1)+1个数先合并一下。
 9 
10 #include <iostream>
11 #include <algorithm>
12 #include <cstring>
13 #include <cstdio>
14 #include <vector>
15 #include <cmath>
16 #include <map>
17 #include <queue>
18 using namespace std;
19 #define LL long long
20 typedef pair<int,int> pii;
21 const int inf = 0x3f3f3f3f;
22 const int MOD = 998244353;
23 const int N = 1e5+10;
24 const int maxx = 200010; 
25 #define clc(a,b) memset(a,b,sizeof(a))
26 const double eps = 1e-8;
27 void fre() {freopen("in.txt","r",stdin);}
28 void freout() {freopen("out.txt","w",stdout);}
29 inline int read() {int x=0,f=1;char ch=getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;}
30 
31 int a[N];
32 int n,m;
33 bool check(int k){
34     queue<LL>q1;
35     queue<LL>q2;
36     if((n-1)%(k-1)!=0){
37         for(int i=1;i<=k-1-(n-1)%(k-1);i++)
38             q1.push(0);
39     }
40     for(int i=1;i<=n;i++){
41         q1.push(a[i]);
42     }
43     LL sum=0;
44     while(1){
45         LL tem=0;
46         for(int i=1;i<=k;i++){
47             if(q1.size()==0&&q2.size()==0) break;
48             int a1,a2;
49             if(q1.size()==0){
50                 tem+=q2.front();
51                 q2.pop();
52                 continue;
53             }
54             if(q2.size()==0) {
55                tem+=q1.front();
56                q1.pop();
57                continue;
58             }
59             a1=q1.front();
60             a2=q2.front();
61             if(a1<a2) {tem+=a1;q1.pop();}
62             else {tem+=a2;q2.pop();}
63         }
64         sum+=tem;
65         if(q1.size()==0&&q2.size()==0) break;
66         q2.push(tem);
67     }
68     if(sum>m) return false;
69     else return true;
70 }
71 
72 int main(){
73     // fre();
74     int T;
75     scanf("%d",&T);
76     while(T--){
77         scanf("%d%d",&n,&m);
78         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
79         sort(a+1,a+1+n);
80         int l=2,r=n;
81         while(l<r){
82             int mid=(l+r)>>1;
83             if(check(mid)) r=mid;
84             else l=mid+1;
85         }
86         printf("%d\n",r);
87     }
88     return 0;
89 }

 

推荐阅读