hdu 5884 Sort (佇列&&二分)
阿新 • • 發佈:2018-12-12
題意:
n個有序序列的歸併排序。每次可以選擇不超過k個序列進行合併,合併代價為這些序列的長度和.總的合併代價不能超過T
, 問k
最小是多少
思路:
二分k,判斷是否成立。
每次要合併k個,但未必會恰好每次都合併k個。所以呢為了代價最小,先合併多餘的那幾個最小的。
(n-1)%(k-1)== 0 是恰好合並k次的判斷條件,為什麼呢?因為合併k個,相當於從n中減去了k-1,n最終應該多出一個,這個靠自己想。
#include <iostream> #include <cstring> #include <queue> #include <algorithm> using namespace std; typedef long long ll; ll a[100000+10]; int t,T,n; queue<int> q1,q2; bool judge(int k) { while(!q1.empty())q1.pop(); while(!q2.empty())q2.pop(); for(int i =1;i<=n;i++) q1.push(a[i]); ll sum = 0,ans = 0;//sum每次merge的花費,ans總花費 if((n-1)%(k-1)!=0) // 為使花費最少,先將多餘的加起來 { int num = (n-1)%(k-1)+1;//重點!+1是因為合併後還會剩一個 for(int i=1;i<=num;i++) { sum+=q1.front(); q1.pop(); } q2.push(sum); ans+=sum; } while(!q1.empty()) { sum = 0; for(int i=1;i<=k;i++) { if(!q1.empty()&&!q2.empty()) { if(q1.front()<=q2.front()) { sum+=q1.front(); q1.pop(); } else { sum+=q2.front(); q2.pop(); } } else if(!q1.empty()) { sum+=q1.front(); q1.pop(); } else if(!q2.empty()) { sum+=q2.front(); q2.pop(); } } ans+=sum; q2.push(sum); } if(ans>T) return false; sum=0; int num=0; while(!q2.empty()) { if(q1.size()==1) break; sum+=q2.front(); q2.pop(); num++; if(num==k) { q2.push(sum); ans+=sum; sum = 0; num = 0; if(q2.size()==1) break; } } if(ans>T) return 0; return 1; } int main() { ios::sync_with_stdio(false); cin>>t; while(t--) { cin>>n>>T; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); int l=2,r=n,mid; int ans = 1; while(l<=r) { mid=(l+r)/2; if(judge(mid)) { ans=mid; r=mid-1; } else l=mid+1; } cout<<ans<<endl; } return 0; }