题干:

Recently, Bob has just learnt a naive sorting algorithm: merge sort. Now, Bob receives a task from Alice. 
Alice will give Bob NN sorted sequences, and the ii-th sequence includes aiai elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than kk sequences in one time. The cost of a merging operation is the sum of the length of these sequences. Unfortunately, Alice allows this program to use no more than TT cost. So Bob wants to know the smallest kk to make the program complete in time.

Input

The first line of input contains an integer t0t0, the number of test cases. t0t0 test cases follow. 
For each test case, the first line consists two integers N (2≤N≤100000)N (2≤N≤100000) and T (∑Ni=1ai<T<231)T (∑i=1Nai<T<231). 
In the next line there are NN integers a1,a2,a3,...,aN(∀i,0≤ai≤1000)a1,a2,a3,...,aN(∀i,0≤ai≤1000).

Output

For each test cases, output the smallest kk.

Sample Input

1
5 25
1 2 3 4 5

Sample Output

3

题目大意:

有n个数,每个数有个值,现在你可以选择每次K个数合并,合并的消耗为这K个数的权值和,问在合并为只有1个数的时候,总消耗不超过T的情况下,最小的K是多少

解题报告:

首先能想到的做法,二分一个K,然后check的时候按照标准k叉哈夫曼树的做法,搞个优先队列,别忘补0(通过n%(k-1)==1这个判断条件不断n++),但是这个做法是nlognlogn的。现在考虑优化:

首先如果是2叉哈夫曼树:

可以设两个数组,一个存放排序后的原数据,一个存放每次相加后的值。对于取之也有几种分析:

1.全部来源于a,此时q为空或者q的队头的元素比a的前两个元素都小.

2.全部来源于b,此时a为空或者a的队头的元素比b的前两个元素都小.

3.a和b中各取一个.

对于k叉:

就一个一个的取,一共取k次,每次取的时候就在两个数组中选一个小的就行了

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#define mod (1000000007)
using namespace std;
typedef long long ll;
int a[200010];
int c[200010];
int b[200010];
int T;
int cal(int n,int k) {
	int i=1;
	int b1=0,cnt=0;
	int x=0;
	int ans=0;
	int add=0,y=k;
	if(k!=2) {
		while((n+add)%(k-1)!=1) add++;
	}
	for(int j=n; j>=1; j--) c[j+add]=a[j];
	for(int j=add; j>=1; j--) c[j]=0;
	n+=add;
	while(true) {
		int x=0;
		int ad=0;
		while((i<=n||b1<cnt)&&x<k) {
			if(i>n) {
				ad+=b[b1];
				ans+=b[b1];
				b1++;
			} else if(b1>=cnt) {
				ad+=c[i];
				ans+=c[i];
				i++;
			} else {
				if(c[i]<b[b1]) {
					ad+=c[i];
					ans+=c[i];
					i++;
				} else {
					ad+=b[b1];
					ans+=b[b1];
					b1++;
				}
			}
			x++;
		}
		if(i>n&&b1>=cnt) {
			break;
		}
		b[cnt++]=ad;
	}
	return ans;
}
int main() {
	int t;
	cin>>t;
	while(t--) {
		int n;
		scanf("%d%d",&n,&T);
		for(int i=1; i<=n; i++) scanf("%d",&a[i]);
		sort(a+1,a+1+n);
		int l=2,r=n;
		int ans;
		while(l<=r) {
			int mid=(l+r)/2;
			if(cal(n,mid)<=T) r=mid-1, ans=mid;
			else l=mid+1;
		}
		printf("%d\n",ans);
	}
	return 0;
}