题目链接:hdu5884 Sort
题意:n
个有序序列的归并排序.每次可以选择不超过k
个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T
, 问k
最小是多少。
题解:先二分k,然后在k给定的情况下,构造k叉哈夫曼树。O(nlogn)
的做法:先对所有数排序,另外一个队列维护合并后的值,取值时从两个序列前端取小的即可。
注:如果(n-1)%(k-1)!=0,那么就要增加(k-1-(n-1)%(k-1))个权值为0的叶子节点作虚拟点。
1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int N = 100005; 7 int n, m; 8 int a[N]; 9 queue<ll>q1, q2; 10 int jud(int k){ 11 while(!q1.empty()) q1.pop(); 12 while(!q2.empty()) q2.pop(); 13 //queue<ll>q1, q2; 14 int i; 15 int tt = (n-1)%(k-1); 16 ll t, s = 0; 17 if(tt){ 18 for(i = 1; i <= k-1 - tt; ++i) 19 q1.push(0);//虚拟点 20 } 21 for(i = 1; i <= n; ++i) 22 q1.push(a[i]); 23 while(1){ 24 t = 0; 25 int x1, x2; 26 for(i = 1; i <= k; ++i){ 27 if(q1.empty() && q2.empty()) 28 break; 29 if(q1.empty()){ 30 t += q2.front(); q2.pop(); 31 continue; 32 } 33 if(q2.empty()){ 34 t += q1.front(); q1.pop(); 35 continue; 36 } 37 x1 = q1.front(); 38 x2 = q2.front(); 39 if(x1 < x2){ 40 t += x1; q1.pop(); 41 }else{ 42 t += x2; q2.pop(); 43 } 44 } 45 s += t; 46 if(q1.empty() && q2.empty()) 47 break; 48 q2.push(t);//维护合并后的值 49 } 50 if(s <= m) return 1; 51 return 0; 52 } 53 void bi_search(){ 54 int l = 2,r = n; 55 while(l < r){ 56 int mid = l + (r - l)/2; 57 if(jud(mid)) 58 r = mid; 59 else 60 l = mid + 1; 61 } 62 printf("%d ", r); 63 } 64 int main(){ 65 int t, i; 66 scanf("%d", &t); 67 while(t--){ 68 scanf("%d%d", &n, &m); 69 for(i = 1; i <= n; ++i) 70 scanf("%d", &a[i]); 71 sort(a+1, a+1+n); 72 bi_search(); 73 } 74 return 0; 75 }