HDU 5884-Sort(佇列+二分)

kewlgrl發表於2016-09-23

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
*/


相關文章