hdu-5884-二分(+玄学)

这个题正确做法是二分K然后去验证

每次验证都是K叉哈弗曼树,也就是排序完了在每次合并最小的K个数

但是要注意一点

开始有N个数字,归并完应该是1个,也就是合并了N-1个

每次归并会把K个数字变成1个,也就是每次减少了K-1个

那么如果N-1不是K-1的倍数,需要优先处理前(N-1)%(K-1)+1个最小的数

以上是正确做法,下面再说玄学事情

1.如果用优先队列会慢很多(很快的都是双队列)

2.存起来输出入的数后必须sort一遍

3.因人而异,有的人写的(如果是优先队列版本)需要加输入优化才能起码不返回TLE

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long int ll;
const int N=100000+5;
int t,n,T,x;
int arr[N];
priority_queue,greater > qu;

bool solve(int k) {
    while(!qu.empty()) qu.pop();
    if(k==1) return false ;
    if(k>n) return true ;
    ll ans=0,sum=0,ls=0;
    if((n-1)%(k-1)!=0) {//如果不能每次合并都是正好K个,先处理前面不足K个的那些数
        ls=(n-1)%(k-1)+1;
        for(int i=1;i<=ls;i++)
            sum+=arr[i];
        ans+=sum;
        qu.push(sum);
    }
    for(int i=ls+1; i<=n; i++)
        qu.push(arr[i]);//把没处理的放进优先队列
    while(qu.size()>=k) {//just K叉哈弗曼树
        sum=0;
        for(int i=1; i<=k; i++) {
            sum+=qu.top();
            qu.pop();
        }
        qu.push(sum);
        ans+=sum;
        if(ans>T) return false ;
    }
    return true;
}

int main()
{
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&T);
        for(int i=1; i<=n; i++)
            scanf("%d",&arr[i]);
        sort(arr+1,arr+1+n);//先排序,不然TLE
        int l=1,r=100000,mid;
        while(l

 

你可能感兴趣的:(HDU)