题目大意:有m本书,每本书有pi页,把这m本书分给k个人抄写,如何分配才能在最短的时间抄写完这m本书。
最大值最小化问题:把一个包含n个正整数的序列划分成m个连续的子序列,设第i个序列的各数之和为S(i), 使得所有S(i)的最大值尽量小。序列最大值为max,所有数之和为sum,则所求答案必定在[max, sum]之间,通过二分法判断中值mid是否符合条件(把序列分为m份,每份均不超过mid)逐步缩小范围,直至求得解。
其实,我觉得还是看代码来的直接,看书上说的东西半天也不理解说的什么意思,还是研究代码可以一点点地理解。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define MAXN 500+10 6 7 long long p[MAXN]; 8 int m, k; 9 bool cut[MAXN]; 10 11 bool judge(long long n) 12 { 13 long long sum = 0; 14 int cnt = 0; 15 for (int i = 0; i < m; i++) 16 { 17 if (sum + p[i] > n) 18 { 19 sum = 0; 20 cnt++; 21 } 22 sum += p[i]; 23 } 24 cnt++; 25 if (cnt > k) return false; 26 return true; 27 } 28 29 int main() 30 { 31 #ifdef LOCAL 32 freopen("in", "r", stdin); 33 #endif 34 int T; 35 scanf("%d", &T); 36 while (T--) 37 { 38 scanf("%d%d", &m, &k); 39 long long sum = 0, lmax = 0; 40 for (int i = 0; i < m; i++) 41 { 42 scanf("%lld", &p[i]); 43 sum += p[i]; 44 lmax = max(lmax, p[i]); 45 } 46 long long low = lmax, high = sum; 47 while (low < high) 48 { 49 long long mid = (low + high) / 2; 50 if (judge(mid)) high = mid; 51 else low = mid + 1; 52 } 53 long long ans = low; 54 int remain = k - 1; 55 memset(cut, 0, sizeof(cut)); 56 sum = 0; 57 for (int i = m-1; i >= 0; i--) 58 { 59 if (i+1 > remain && sum + p[i] <= ans) 60 { 61 sum += p[i]; 62 } 63 else 64 { 65 cut[i] = true; 66 sum = p[i]; 67 remain--; 68 } 69 } 70 for (int i = 0; i < m; i++) 71 { 72 printf("%lld%s", p[i], (i == m-1) ? " " : " "); 73 if (cut[i]) printf("/ "); 74 } 75 } 76 return 0; 77 }
最后的输出把我纠结地快疯了,本来也不是很麻烦,可是因为参考别人代码一会就把自己弄迷糊了,果然有些东西还是按自己思路写更自然、快速。