1. 程式人生 > >HDU - 5884 Sort (二分答案+貪心)

HDU - 5884 Sort (二分答案+貪心)

sca 優先 scan n) empty 每次 都是 scanf light

有n個數字,你需要把這n個數字合成一個數字,每次只能把k個數字合並成一個,花費為這k個數字的和。

給一個最大花費,問不超過這個最大花費的情況下,k的最小值。

Sample Input
1
5 25
1 2 3 4 5

Sample Output
3

這個題很容易想到二分答案+優先隊列check

然而這樣復雜度是 O(n logn*logn ),會TLE(這特麽都會TLE?加個讀入優化就過了)

可以先給所有數字排個序,然後用兩個隊列,一個存原來的數字,一個存新合成的數字。

所以兩個隊列都是有序的。每次取的時候比較那個隊列的第一個數小,就從哪一個裏面取。這樣復雜度是O(nlogn)的。

然後有一個坑點。你是要把n個數合並成一個,那麽說你要減少n-1個數。每次只能減少 k-1 個數。

那麽當 (n-1) % (k-1) != 0 時,就一定不能正好最優合並,所以要添加 k-1 - (n-1)%(k-1) 個0,來補齊。

開long long。否則就WA。很真實。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>

using namespace
std; typedef long long LL; const int maxn =100000 +100; int T; int a[maxn]; int n, p; bool check(int mid) { LL cost = 0; queue<LL> q1, q2; int t = (n-1) % (mid-1); if (t != 0) for (int i = 1; i <= mid-1-t; i++) q1.push(0); for (int i = 1; i <= n; i++) q1.push(a[i]);
while(q1.size() + q2.size() > 1) { LL pp = 0; for (int i = 1; i <= mid; i++) { if (!q1.empty() && !q2.empty()) { if (q1.front() < q2.front()) pp += q1.front(), q1.pop(); else pp += q2.front(), q2.pop(); } else if (!q1.empty()) pp+= q1.front(), q1.pop(); else if (!q2.empty()) pp+= q2.front(), q2.pop(); else break; } cost += pp; q2.push(pp); } return cost <= p; } int main() { int T; scanf("%d", &T); for (int t = 1; t <= T; t++) { scanf("%d%d", &n, &p); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a+1, a+1+n); int l = 2, r = n, ans; while(l <= r) { int mid = (l+r)/2; if (check(mid)) ans = mid, r = mid-1; else l = mid+1; } printf("%d\n", ans); } return 0; }

HDU - 5884 Sort (二分答案+貪心)