对于给定的一个长度为N的正整数数列A[i],现要将其分成M(M≤N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列4 2 4 5 1要分成3段
将其如下分段:
[4 2][4 5][1]
第一段和为6,第2段和为9,第3段和为1,和最大值为9。
将其如下分段:
[4][2 4][5 1]
第一段和为4,第2段和为6,第3段和为6,和最大值为6。
并且无论如何分段,最大值不会小于6。
所以可以得到要将数列4 2 4 5 1要分成3段,每段和的最大值最小为6。
输入格式:
输入文件divide_b.in的第1行包含两个正整数N,M,第2行包含N个空格隔开的非负整数A[i],含义如题目所述。
输出格式:
输出文件divide_b.out仅包含一个正整数,即每段和最大值最小为多少。
输入样例#1:
5 3
4 2 4 5 1
输出样例#1:
6
对于20%的数据,有N≤10;
对于40%的数据,有N≤1000;
对于100%的数据,有N≤100000,M≤N, A[i]之和不超过10^9。
二分答案,
首先我们确定好一个mid,表示最大值为mid是否可行
然后枚举整个数列,记录下一个tot,表示这个数列中最大值不超过mid,需要分成的段数
如果tot<m,说明这个mid是可行的,因为我们要是分m段的话,只会分的越来越小
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<cmath>
5 using namespace std;
6 const int MAXN=100001;
7 void read(int & n)
8 {
9 char c='+';int x=0;
10 while(c<'0'||c>'9')
11 c=getchar();
12 while(c>='0'&&c<='9')
13 {
14 x=x*10+(c-48);
15 c=getchar();
16 }
17 n=x;
18 }
19 int n,m;
20 int a[MAXN];
21 int pd(int num)
22 {
23 int now=0;
24 int tot=0;
25 for(int i=1;i<=n;i++)
26 {
27 if(now+a[i]<num)
28 now=now+a[i];
29 else if(now+a[i]==num)
30 now=0,tot++;
31 else if(now+a[i]>num)
32 now=a[i],tot++;
33 }
34 if(now)
35 tot++;
36 if(tot>m)
37 return 0;
38 else
39 return 1;
40 }
41 int main()
42 {
43 read(n);read(m);
44 int maxn=-1;
45 for(int i=1;i<=n;i++)
46 {
47 read(a[i]);
48 maxn=max(a[i],maxn);
49 }
50 if(n==m)
51 {
52
53 cout<<maxn;
54 return 0;
55 }
56 int l=maxn,r=1000000000;
57 while(l<r)
58 {
59 int mid=(l+r)>>1;
60 if(pd(mid)==1)
61 r=mid;
62 else
63 l=mid+1;
64 }
65 printf("%d",r);
66 return 0;
67 }