HDU 5884 Sort (二分)

时间:2023-03-08 16:58:23

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5884

nn个有序序列的归并排序.每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过TT, 问kk最小是多少

用一个队列维护合并的数,二分一下判断合理性。注意一点的是要是(n - 1)%(k - 1) != 0的话,就要先合并前(n - 1)%(k - 1) + 1项,这样会更优一点。还有细节问题很多要注意。

 //#pragma comment(linker, "/STACK:102400000, 102400000")
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair <int, int> P;
const int N = 1e5 + ;
LL a[N], m;
int n; bool judge(int k) {
queue <int> que;
while(!que.empty()) {
que.pop();
}
int sum = , i = ;
if((n - )%(k - )) {
for( ; i <= (n - ) % (k - ) + ; ++i) {
sum += a[i];
}
que.push(sum);
}
int ans = sum;
for(; i <= n || !que.empty(); ++i) {
if(que.size() <= && i > n)
break;
int cnt = k, ok = ;
sum = ;
while(cnt--) {
if((que.size() && que.front() < a[i])|| i > n) {
sum += que.front();
que.pop();
} else {
ok = ;
sum += a[i++];
}
}
if(ok) {
--i;
}
ans += sum;
que.push(sum);
}
return ans <= m;
} int main()
{
int t;
scanf("%d", &t);
while(t--) {
scanf("%d %lld", &n, &m);
for(int i = ; i <= n; ++i) {
scanf("%lld", a + i);
}
sort(a + , a + n + );
int l = , r = n;
while(l < r) {
int mid = (l + r) / ;
if(judge(mid)) {
r = mid;
} else {
l = mid + ;
}
}
printf("%d\n", r);
}
return ;
}