http://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1919
Description
晴天想把一个包含n个整数的序列a分成连续的若干段,且和最大的一段的值最小,但他有强迫症,分的段数不能超过m段,然后他就不会分了。。。他想问你这个分出来的和最大的一段的和最小值是多少?
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行为两个整数n,m分别代表序列的长度和最多可分的段数。
接下来一行包含n个整数表示序列。
0<=n<=50000 1<=m<=n,0<=ai<=10000。
Output
输出一个整数表示和最大的一段的最小值。
Sample Input
1 3 2 1 3 5
Sample Output
5
HINT
1 3 5 分成一段可以为1 3 5和为9,分成两段可以为1,3 5或者1 3,5,和最大的一段值分别为8,5,所以答案为5
#include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <vector> #include <algorithm> #include <map> #include <queue> #include <stack> #include <math.h> using namespace std; #define INF 0x3f3f3f3f const int maxn = 61000; typedef long long LL; int a[maxn]; int n, m; int Judge(int sum) { int ans = 0; int cnt = 0; for(int i=1; i<=n; i++) { if(ans+a[i]>sum)///判断以sum为一段的最大值 能有几段 { ans=a[i]; cnt++; if(cnt>=m) return 0;///如果超过m段,则返回0 } else ans+=a[i]; } return 1; } int main() { int T; scanf("%d", &T); while(T --) { scanf("%d %d", &n, &m); int maxs = 0; int sum = 0; for(int i=1; i<=n; i++) { scanf("%d", &a[i]); maxs=max(maxs, a[i]); sum += a[i]; } int l=maxs; int r=sum; int ans; while(l<=r)///所求值一定在maxs和sum之间,从中选出最小的 { int mid=(l+r)/2; if(Judge(mid))///若mid满足分m段最大值为mid,则缩小r,判断是否还有最优解 { ans = mid; r = mid-1; } else l=mid+1;///若不满足,则加大l的值 } printf("%d ", ans); } return 0; }