1. 程式人生 > >Uva LA 3177 - Beijing Guards 貪心,特例分析,判斷器+二分,記錄區間內狀態數目來染色 難度: 3

Uva LA 3177 - Beijing Guards 貪心,特例分析,判斷器+二分,記錄區間內狀態數目來染色 難度: 3

\n pac problem mit local ide 貪心 item code

題目

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1178


題意

圓桌上有n個人,每個人要求a_i種不同的禮物,相鄰兩個人的禮物不能重復,問有至少要準備多少種禮物

思路

如劉書

1. 明顯,若n=1,直接輸出a[0]

2. 若n為偶數,則可以形如ABABAB,直接取最大的兩個相連之和

3. 若n為奇數,則可以轉化為二分判斷問題。

但如何判斷x種禮物能否滿足要求呢?n * r狀態約為1e10,明顯太大不能承受。

假設送第0個人,0~a[0]-1這a[0]種禮物,那麽第n-1個人明顯不能再拿到這a[0]種禮物了。

要找到一個貪心的原則,

由於第n-1個人編號為偶數,那麽,偶數的人盡量取a[0]~x-1這些禮物,奇數的人盡量取0~a[0]-1這些禮物就可以。

但是這樣如果記錄每個狀態時還是會出現麻煩。

那麽,直接令r[i]記錄第i個人拿到0~a[0]-1範圍內禮物的數目,l[i]為a[0]~x-1這些禮物的數目,就能記錄其狀態的同時保持計算傳遞。

感想

1. 一開始沒有註意到如果是奇數,如ABABA這種情況就會挨在一起了

2. 後來沒有想到可以在延展過程中逐漸替換掉一小部分結果,而是以為要直接找個第三個最小元素的換掉,這樣結果就太大了

3. 最後是沒有註意到特例n=1的存在。

代碼

技術分享圖片
#include <algorithm>
#include 
<cassert> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <queue> #include <set> #include <tuple> #define LOCAL_DEBUG using namespace std; const int MAXN = 1e5 + 4; int a[MAXN]; int r[MAXN], l[MAXN];
int n; bool check(int kindNum) { int rlimit = a[0]; int llimit = kindNum - rlimit; r[0] = rlimit; l[0] = 0; for (int i = 1; i < n; i++) { if (i & 1) { r[i] = min(rlimit - r[i - 1], a[i]); l[i] = a[i] - r[i]; if (l[i] > llimit - l[i - 1]) { assert(false); return false; } } else { l[i] = min(llimit - l[i - 1], a[i]); r[i] = a[i] - l[i]; if (r[i] > rlimit - r[i - 1]) { assert(false); return false; } } } return r[n - 1] == 0; } int main() { #ifdef LOCAL_DEBUG freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\input.txt", "r", stdin); //freopen("C:\\Users\\Iris\\source\\repos\\ACM\\ACM\\output.txt", "w", stdout); #endif // LOCAL_DEBUG for (int ti = 1; scanf("%d", &n) == 1 && n; ti++) { int ans = 0; for (int i = 0; i < n; i++) { scanf("%d", a + i); if (i)ans = max(ans, a[i] + a[i - 1]); } ans = max(ans, a[n - 1] + a[0]); if (n == 1) ans = a[0]; else if (n & 1) { int mxAns = 2 * ans + 1; while (ans < mxAns) { int mid = (ans + mxAns) >> 1; if (check(mid)) { mxAns = mid; } else { ans = mid + 1; } } } printf("%d\n", ans); } return 0; }
View Code

Uva LA 3177 - Beijing Guards 貪心,特例分析,判斷器+二分,記錄區間內狀態數目來染色 難度: 3