【最优K叉树】hdu 5884 Sort
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的虚结点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 typedef long long ll; 10 int n; 11 ll t; 12 const int maxn=1e5+3; 13 ll a[maxn]; 14 bool judge(int mid){ 15 int cnt=(n-1)/(mid-1); 16 queue<ll> Q; 17 if((n-1)%(mid-1)!=0){ 18 cnt++; 19 for(int i=0;i<(mid-1-(n-1)%(mid-1));i++){ 20 Q.push(0); 21 } 22 } 23 ll ans=0; 24 int l=0; 25 while(cnt--){ 26 ll tmp=0; 27 for(int i=0;i<mid;i++){ 28 if(!Q.empty()&&(l>=n||Q.front()<=a[l])){ 29 tmp+=Q.front(); 30 Q.pop(); 31 }else{ 32 tmp+=a[l++]; 33 } 34 } 35 ans+=tmp; 36 Q.push(tmp); 37 } 38 if(ans<=t) return true; 39 return false; 40 } 41 int main(){ 42 int T; 43 scanf("%d",&T); 44 while(T--){ 45 scanf("%d%lld",&n,&t); 46 for(int i=0;i<n;i++){ 47 scanf("%lld",&a[i]); 48 } 49 sort(a,a+n); 50 int l=2,r=n; 51 while(l<=r){ 52 int mid=(l+r)>>1; 53 if(judge(mid)){ 54 r=mid-1; 55 }else{ 56 l=mid+1; 57 } 58 } 59 printf("%d\n",l); 60 } 61 return 0; 62 }
#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+3; ll a[maxn]; bool judge(int mid){ queue<ll> Q1,Q2; for(int i=0;i<n;i++) Q1.push(a[i]); if((n-1)%(mid-1)!=0){ for(int i=0;i<(mid-1-(n-1)%(mid-1));i++){ Q2.push(0); } } ll ans=0; while(Q1.size()+Q2.size()>=mid){ ll tmp=0; for(int i=0;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=0;i<n;i++){ scanf("%lld",&a[i]); } sort(a,a+n); int l=2,r=n; while(l<=r){ int mid=(l+r)>>1; if(judge(mid)){ r=mid-1; }else{ l=mid+1; } } printf("%d\n",l); } return 0; }