题目链接
一开始看到题的时候,竟然读成了是按照升序排序的一串数,害得我WA了两发,还以为是补0补错了,研究了一会补0发现好像没有多大问题,然后就继续了,直到再看了遍题,发现好像是没有给你拍好序的,然后AC……
这道题其实哈夫曼树不难,就是补0思想挺好的,遇到一串数字,我们要对它建立哈夫曼树,我们总不能做到最后才补0吧,就得早些把0给放进去,这样子基数小,才能建立最小的哈夫曼树,那么得放多少个0呢?我们假如要建立一棵X叉的哈夫曼树,那么每次的叶子节点就要有X个节点才行,假如,我们拿出一个节点,剩余就是(N-1)个节点,这剩余的(N-1)个节点必须是(X-1)的整数倍才能构成一棵完全的X叉树,因为,我们对于每个(X-1)个节点都能加上之前取出来的“1”合并成一个新的“1”节点,然后继续合并,最终合并成一个节点,所以(N-1)%(X-1)所多出来的节点就是多出来的节点,我们要补上X-1-多出来的节点才行,这些就都是“0”节点来补了。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ll INF = (ll)1<<61;
const int maxN = 100005;
int N;
ll K;
ll a[maxN];
bool check(int x)
{
queue<ll> Q1;
queue<ll> Q2;
for(int i=1; i<=x-((N-1)%(x-1))-1; i++) Q1.push(0);
for(int i=1; i<=N; i++) Q1.push(a[i]);
ll sum = 0;
while(!Q1.empty() || !Q2.empty())
{
int tmp = x;
ll inque = 0;
while(tmp--)
{
ll e1 = INF, e2 = INF;
if(Q1.empty() && Q2.empty()) break;
if(!Q1.empty()) e1 = Q1.front();
if(!Q2.empty()) e2 = Q2.front();
if(e1 <= e2)
{
sum += e1;
inque += e1;
Q1.pop();
}
else
{
sum += e2;
inque += e2;
Q2.pop();
}
}
if(Q1.empty() && Q2.empty()) break;
Q2.push(inque);
}
return sum<=K;
}
int solve(int L, int R)
{
int ans = N;
int mid = (L + R)>>1;
while(L<=R)
{
mid = (L + R)>>1;
if(check(mid)) { ans = mid; R = mid - 1; }
else L = mid + 1;
}
return ans;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%lld", &N, &K);
for(int i=1; i<=N; i++) scanf("%lld", &a[i]);
sort(a+1, a+1+N);
printf("%d\n", solve(2, N));
}
return 0;
}