HDU 5884-Sort(队列+二分)

25 篇文章 1 订阅

Sort

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1631    Accepted Submission(s): 418


Problem Description
Recently, Bob has just learnt a naive sorting algorithm: merge sort. Now, Bob receives a task from Alice.
Alice will give Bob   sorted sequences, and the  -th sequence includes   elements. Bob need to merge all of these sequences. He can write a program, which can merge no more than   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   cost. So Bob wants to know the smallest   to make the program complete in time.
 

Input
The first line of input contains an integer  , the number of test cases.   test cases follow.
For each test case, the first line consists two integers   and  .
In the next line there are   integers  .
 

Output
For each test cases, output the smallest  .
 

Sample Input
  
  
1 5 25 1 2 3 4 5
 

Sample Output
  
  
3
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5900  5899  5898  5897  5896 

题目意思:

n个元素的序列做归并排序,每次可以选择不超过kk个序列进行合并,合并代价为这些序列的长度和,总的合并代价不能超过TT, 求一个最小的kk


解题思路:

先升序排列数组,再判断对于当前的k,序列能否被恰好分割。如果不能,就先取(n-1)%(k-1)+1个数归并一次;之后每次从两个队头取出k个数出来合并,判断与T的大小关系。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <iomanip>
#include <algorithm>
#include <queue>
#define maxn 200010
#define INF 0xfffffff
using namespace std;

int n;
long long x[maxn],T;
queue<int> que1,que2;
bool Valid(int k)
{
    long long sum=0,ans=0;
    while(!que1.empty()) que1.pop();//没有clear()所以只能手动清空
    while(!que2.empty()) que2.pop();
    for(int i=0; i<n; ++i)//把数组元素压入队列一
        que1.push(x[i]);
    if((n-1)%(k-1)!=0)//如果不能恰好分割
    {
        int num=(n-1)%(k-1)+1;
        for(int i=0; i<num; ++i)
        {
            sum+=que1.front();
            que1.pop();
        }
        que2.push(sum);
        ans+=sum;
    }
    //每次从两个队头取出k个数出来合并
    while(!que1.empty())
    {
        sum=0;
        for(int i=0; i<k; ++i)
        {
            if(!que1.empty() &&!que2.empty())
            {
                if(que1.front()<=que2.front())
                {
                    sum+=que1.front();
                    que1.pop();
                }
                else
                {
                    sum+=que2.front();
                    que2.pop();
                }
            }
            else if(que1.empty())
            {
                sum+=que2.front();
                que2.pop();
            }
            else if(que2.empty())
            {
                sum+=que1.front();
                que1.pop();
            }
        }
        ans+=sum;
        que2.push(sum);
    }
    if(ans>T) return false;//此时的k不满足
    sum=0;
    while(!que2.empty())
    {
        for(int i=0; i<k; ++i)
        {
            if(i==k-1)//保证取k个数
            {
                que2.push(sum);
                ans+=sum;
                sum=0;
            }
            if(que2.empty()) break;//不足k个数
            sum+=que2.front();
            que2.pop();
        }
    }
    if(ans>T) return false;
    return true;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%I64d",&n,&T);
        for(int i=0; i<n; ++i)
            scanf("%I64d",&x[i]);
        sort(x,x+n);//注意要先排个序
        int low=1,high=n-1,k,ans=1;
        while(low<=high)
        {
            k=(low+high)/2;
            if(Valid(k))//当前k满足条件,区间缩成左半边
            {
                high=k-1;
                ans=k;
            }
            else low=k+1;
        }
        printf("%d\n",ans);//当前k不满足条件,区间缩成右半边
    }
    return 0;
}

/*
1
5 25
1 2 3 4 5
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值