Ice Cream Tower Gym - 101194D (二分答案、貪心檢驗)
阿新 • • 發佈:2018-12-11
題目:傳送門
Solution:
二分答案和貪心檢驗就是這道題思路的核心,我來詳細介紹一下其中的過程,直接算可以製造冰激凌的數量的話很困難,我感覺主要是有一個k的存在使得直接計算不好去想(我是不會的。。),但是檢驗的話就很好操作了,我們可以用二分的方法去一步一步縮小答案區間,最後就可以找到最大值了。
那麼該如何檢驗呢?為了使得數量最大,我們每次肯定挑最小的那個放在頂層,然後找它的下面一層。舉個例子,如果我們要驗證是否能製作x個,我們就先挑出最小的x個來作為頂層,然後從x + 1開始遍歷一遍依次放在這x個的下一層,直到最後。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 3 * 1e5 + 100; ll cake[maxn], a[maxn]; int t, n, k; bool check(int x) //貪心檢驗 { if(!x) return true; int j = x + 1; for(int i = 1; i <= n; ++i) cake[i] = a[i]; int i; for(i = x + 1; i <= n; ++ i) { while(i <= n && cake[j - x] * 2 > a[i]) i++; if(i > n) return false; cake[j++] = a[i]; if((j - 1) / x >= k) return true; } if((j - 1) / x >= k) return true; else return false; } int Research(int l, int r) //二分答案 { int res = -1; while(l <= r) { int mid = (l + r) >> 1; if(check(mid)) { res = mid; l = mid + 1; } else { r = mid - 1; } } return res; } int main() { //freopen("in.txt", "r", stdin); int s = 0; cin >> t; while(t --) { cin >> n >> k; for(int i = 1; i <= n; ++ i) { scanf("%lld", &a[i]); } sort(a + 1, a + 1 + n); int ans = Research(0, n / k); printf("Case #%d: ", ++ s); cout << ans << endl; } return 0; }