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得复杂度了!
这个题目的标准复杂度是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; }
相关文章推荐
- HDU 5884 Sort(2016年青岛网络赛 G 二分+贪心+小优化)
- 2016 青岛区域赛网络赛1003 HDU 5880 Family View
- HDU 5884 青岛网络赛(二分加维护队列)
- HDU 5884 Sort(二分加双队列优化)
- HDU 5878 I Count Two Three (打表+二分查找) -2016 ICPC 青岛赛区网络赛
- HDU 5879 - Cure【2016 ACM 区域赛青岛赛区网络赛】
- hdu 5884 Sort 二分+K哈夫曼树(解决不单调问题) 队列优化
- hdu 5884 Sort 二分+哈夫曼树(解决不单调问题) 队列优化
- 2016 ACM/ICPC 青岛区域赛网络赛 1001 I Count Two Three(打表+二分)
- hdu 5884 Sort 2016ACM/ICPC青岛赛区网络赛1007
- HDU 5884 Sort -2016 ICPC 青岛赛区网络赛
- hdu 5881 Tea (2016 acm 青岛网络赛)
- [2016ICPC 青岛网络预选赛] HDU 5889 网络流
- 2016 ACM/ICPC 青岛区域赛网络赛 1005 Balanced Game (找规律)
- hdu 5882 Balanced Game 2016ACM/ICPC青岛赛区网络赛1005
- [2016ICPC 青岛网络预选赛] HDU 5879 数列求和
- 2016 ACM/ICPC Asia Regional Qingdao Online hdu 5884 Sort (二分+优先队列)★
- hdu 5883 The Best Path 2016ACM/ICPC青岛赛区网络赛1006
- hdu 3717 Rescue 二分加队列优化(技巧)
- hdu 5889 Barricade 2016ACM/ICPC青岛赛区网络赛1011