题目链接
一眼看见就是二分, 主要是check怎么写,首先我先想的是从最小开始,一次合并k-1个,最后处理一下不足k-1个的部分,结果wa了,,后来参考大佬博客,
这题必须用优先队列写,每次合并的应该是序列中最小的值(即k叉哈夫曼树),,这题其实不难,我真是菜到家了。。。。哎。。。
ps.注意处理不足k-1的余数。
下面是ac代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5+10;
int t, n;
int a[N], sum[N];
priority_queue< int, vector<int>, greater<int> > q;
bool check(int k)
{
while(q.size()) q.pop();
int m = (n - 1) % (k - 1);
int res = 0;
if (m)
{
m++;
res += sum[m];
q.push(res);
}
for (int i = m + 1; i <= n; i++) q.push(a[i]);
int cnt = (n - 1) / (k - 1);
for (int i = 0; i < cnt; i++)
{
int tk = k, tt = 0;
while(tk--)
{
tt += q.top();
res += q.top();
q.pop();
}
q.push(tt);
}
if (res > t) return 0;
else return 1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &t);
sum[0] = 0;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++)
sum[i] = sum[i-1] + a[i];
int l = 2, r = n, mid;
while(l < r)
{
mid = (l + r) >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
if (n <= 1) r = 1;
printf("%d\n", r);
}
return 0;
}