UVa 714 Copying Books 二分 + 貪心 (最大值最小化問題)
阿新 • • 發佈:2019-02-17
/** * 最大值最小化問題: 二分法。 劉汝佳那本白書上也說的很詳細。 * 先把最大值的可能區間計算出來,也就是[0, maxAns] maxAns 就是所有頁數總和。 * 然後再在答案區間裡先把“最大值最小化”。 * 得到最小化後的最大值以後,就可以根據這個最大值來對最終答案進行計算。 * 如何分割槽,也就是計算最後答案ans: 這裡就要用到貪心思想,因為題目要求 * 如果有多種可能情況,讓區間集合所含的元素數從小到大排列。這樣就可以貪心地 * 從所有pages的最後一個元素往前遍歷來進行劃分區間,只要其總和不大於之前所求的最大值, * 就歸到那個區間。 * 在把所有區間分好後,還有個情況就是,這個時候可能需要3個斜槓來分4個區間, * 然而只用了2個(比如樣例2),這樣還有一個斜槓沒用到,就再用貪心,把pages從第一個開始往後掃, * 如果當前pages不用劃斜槓,而剩餘斜槓數大於0,則在這裡添個斜槓。 */ #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <algorithm> #define INF 0x7fffffff #define MAXS 501 #define LL long long using namespace std; int m, k; LL maxAns; int pages[MAXS], ans[MAXS]; bool judge(LL x) { int sum = 0, t = k; for(int i = 0; i < m; i ++) { sum += pages[i]; if(sum > x) { i --; sum = 0; t --; } if(!t) { if(i != m - 1) return false; else return true; } } return true; } void solve() { memset(ans, 0, sizeof(ans)); LL l, r, cur; l = 0; r = maxAns; while(l < r) { cur = (l + r) / 2; if(judge(cur)) r = cur; else l = cur + 1; } int sum = 0; for(int i = m - 1; i >= 0; i --) { sum += pages[i]; if(sum > r) { sum = 0; ans[++ i] = 1; k --; } } int i = 1; while(k > 1) { for(; i < m; i ++ ) { if(!ans[i]) { ans[i] = 1; k --; break; } } } printf("%d", pages[0]); for(int i = 1; i < m; i ++) { if(ans[i]) printf(" /"); printf(" %d", pages[i]); } printf("\n"); } int main() { int t; scanf("%d", &t); while(t --) { maxAns = 0; scanf("%d%d", &m, &k); for(int i = 0; i < m; i ++) { scanf("%d", &pages[i]); maxAns += pages[i]; } solve(); } return 0; }