Sort
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3231 Accepted Submission(s): 801
Problem Description
Recently, Bob has just learnt a naive sorting algorithm: merge sort. Now, Bob receives a task from Alice.
Alice will give Bob N sorted sequences, and the i -th sequence includes ai elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than k 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 T cost. So Bob wants to know the smallest k to make the program complete in time.
Alice will give Bob N sorted sequences, and the i -th sequence includes ai elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than k 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 T cost. So Bob wants to know the smallest k to make the program complete in time.
Input
The first line of input contains an integer
t0
, the number of test cases.
t0
test cases follow.
For each test case, the first line consists two integers N (2≤N≤100000) and T (∑Ni=1ai<T<231) .
In the next line there are N integers a1,a2,a3,...,aN(∀i,0≤ai≤1000) .
For each test case, the first line consists two integers N (2≤N≤100000) and T (∑Ni=1ai<T<231) .
In the next line there are N integers a1,a2,a3,...,aN(∀i,0≤ai≤1000) .
Output
For each test cases, output the smallest
k
.
Sample Input
1 5 25 1 2 3 4 5
Sample Output
3
Source
Recommend
wange2014
题意:
n个有序序列的归并排序。每次可以选择不超过k
个序列进行合并,合并代价为这些序列的长度和.总的合并代价不能超过T
, 问k
最小是多少。
思路: (队友shilongbao整理的思路很好)
很明显的二分,因为如果k==n, 那么是最小的, 同理递减。关键是考虑怎么check.一开始觉得不就是个哈夫曼吗...也没想出什么反例,但是总感觉有嗲不对..然后一直T,加了Fastio还是T.
最后发现可能存在影响二分单调性的情况,也就是说当 (n-1)%(k-1)!=0,这时候如果还是每次取k个合并在放进去,最后剩下的不足k个全部取出合并所需要的花费,比先合并(n-1)%(k-1)+1个的最小的花费是大的.
至于为什么是(n-1)%(k-1) 因为你每取出k个数,合并后成1个数列,少了k-1个.n个数列最后合并成一个,少了n-1个.
这个题如果还采用哈夫曼树check的话,如果不加超级输入挂还是会T的.
我们这里其实完全不用,因为我们可能要提前合并最小的几个数,所以我们将序列先排序,然后开两个队列,一个是存放原始的数,一个是存放新合成的,因为这个序列原本有序了,所以在队列中也分别是有序的,这样每次在两个有序的序列中取k个就可以啦.
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 1e5 + 7;
const int INF = 2e9;
int a[maxn], n;
int check(int k)
{
int ans = 0;
queue<int> q, tmp;
for(int i = 1; i <= n; i++) q.push(a[i]);
if((n-1) % (k-1))
{
int x = (n-1) % (k-1) + 1;
while(x--)
{
ans += q.front();
q.pop();
}
tmp.push(ans);
}
while(1)
{
if(q.size() + tmp.size() == 1 || q.size() + tmp.size() == 0) break;
int x, y, sum = 0;
for(int i = 1; i <= k; i++)
{
if(q.size()) x = q.front();
else x = INF;
if(tmp.size()) y = tmp.front();
else y = INF;
if(x <= y) sum += x, q.pop();
else sum += y, tmp.pop();
}
ans += sum;
tmp.push(sum);
// cout << sum << endl;
}
// cout << ans << endl;
return ans;
}
int main()
{
int _, t;
cin >> _;
while(_--)
{
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, mid, ans;
while(l <= r)
{
mid = (l+r)>>1;
if(check(mid) <= t)
ans = mid, r = mid - 1;
else
l = mid + 1;
// cout << mid <<endl;
}
printf("%d\n", ans);
}
return 0;
}