题目:uva714 - Copying Books(最大值最小化)
题目大意:给出n本书,每本书的值代表这本书的页数。然后给定m个scribers,每个scriber至少要抄一本书,或者连续的几本书。每个scriber的工作量就等于他要抄的书的页数之和。问怎样划分能使的scribers中工作量的最大值最小。这里要求答案如果有多种的话就输出前面的和比较小的那个划分。
解题思路:最大值最小化问题。
二分尝试可能的最大值,然后如果在这个最大值的情况下可以划分的话,说明最大值可能是这个值,也可能更小。如果不能划分的话说明这个最大值不够大。
划分的时候从后面往前面划分,保证后面的比较大。
代码:
#include <stdio.h> #include <string.h> const int N = 505; typedef long long ll; int n, m; ll max_num, min_num; int books[N]; int visit[N]; ll Min (const ll a, const ll b) { return a < b ? a : b; } int divide (ll value) { int i = n - 1; int count = 0; ll sum; while (i >= 0) { sum = 0; if (sum + books[i] > value) return m + 1; while (i >= 0 && sum + books[i] <= value) { sum += books[i--]; } if (i >= 0) visit[i] = 1; count++; } return count; } int bsearch () { ll left = min_num; ll right = max_num; ll mid; while (left < right) { mid = left + ((right - left)>>1); if (divide (mid) <= m) right = mid; else left = mid + 1; } return right; } void solve () { ll ans = bsearch(); memset (visit, 0, sizeof (visit)); int cnt = divide (ans); for (int i = 0; i < n - 1 && cnt < m; i++) { if (!visit[i]) { visit[i] = 1; cnt++; } } } int main () { int t; scanf ("%d", &t); while (t--) { max_num = 0; scanf ("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf ("%d", &books[i]); max_num += books[i]; if (i == 0) min_num = books[i]; else min_num = Min(min_num, books[i]); } memset (visit, 0, sizeof (visit)); if (m != 1) solve(); for (int i = 0; i < n - 1; i++) { printf ("%d ", books[i]); if (visit[i]) printf ("/ "); } printf ("%d\n", books[n - 1]); } return 0; }
uva714 - Copying Books(最大值最小化)
时间: 2024-10-06 01:47:43