您的位置:首页 > 理论基础 > 计算机网络

hdu 5548 sort 2016青岛区域赛网络赛 二分+队列优化

2016-09-17 22:57 441 查看
传送门:hdu 5548 sort

这个题目的标准复杂度是o(n*lgn),据说如果多乘一个lgn优化一个输入还是可以过得!也就是使用优先队列的做法!

这个题目还有一个坑点就是不能每次只是贪心,就比如说枚举到k=4的时候1,2,3,4,5这个数列的最小值是先把前两个合并变为数列3,3,4,5然后在进行合并才是最少的花费,这样的花费是3+15=18,然而如果按照贪心的思路去做,第一次先枚举前四个那么第一次过后数列就变为10,5这样的花费就变为10+10+5=25了,怎么才能保证结果是花费的最小呢?我们只需要保证最后一次取得是k个就可以了!那么下一个问题就是怎么保证最后一次取得是k个呢?

我们来想一下如果按照每次都是取k个来说,每次失去的就是k-1个数,所以我们只需要第一次合并(N-1)%(k-1)+1,{(N-1)%(k-1)这个值为0的话就不用+1了}就可以了!

那怎么保证复杂度呢?我们只需要申请两个队列就可以,把每次合并完的放到新的队列里面,每次取得时候取得是这个两个队列的最小值就可以!这样就nlgn得复杂度了!

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MX = 100000 + 5;
const LL INF = 1e18;

int seq[MX << 2], N;
LL T;

bool check(int n) {
while(!que.empty()) que.pop();
while(!tq.empty())  tq.pop();
int fl = (N - 1) % (n - 1);
int md = fl ? fl + 1 : 0;
int st = N + 1 - (n - md);
if(fl) for(int i=1;i<=n-md;i++) que.push(0);
for(int i = 1; i <= N ; i++) que.push(seq[i]);
LL ans = 0;
while((que.size() + tq.size()) > 1) {
LL tmp = 0;
for(int i = 0; i < n; i++) {
LL A = INF, B = INF;
if(que.empty() && tq.empty())  {
ans += tmp;
goto END;
}
if(!que.empty()) A = que.front();
if(!tq.empty())  B = tq.front();
if(A <= B) {
tmp += A;
que.pop();
} else {
tmp += B;
tq.pop();
}
}
ans += tmp;
tq.push(tmp);
}
END:;
if(ans > T) return false;
return true;
}

void solve() {
int l = 2, r = N, mid,ans=0;
while(l<=r) {
mid  = (l + r) >> 1;
if(check(mid)) {
ans  = mid;
r = mid-1;
} else l = mid+1;
}
printf("%d\n", ans);
}
int main(void) {
int _;
//freopen("in.txt", "r", stdin);
cin >> _;
while(_--) {
scanf("%d%I64d", &N, &T);
for(int i = 1; i <= N; i++) scanf("%d", &seq[i]);
sort(seq +1, seq +1 + N );
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: