题目大意
- 给出 n 个数字,分成 m 段;
- 每一段的和 s,要求 s 的最大值尽可能小。
题目分析
解题思路:
- 初始的左边界L:一定是数组的最大值,因为最小的值,也必须有一个数字在里面;
- 初始的左边界R:是数组的和,因为可能m的值是1,全部人都在同一组;
- 二分的while()循环,看起来没有难度,但是结束条件才是精髓:本题解用的是 while( l+1<r) ,在执行完二分之后,并不是得到一个值,而是得到 l 和 r 两个值,最后特判一下;
- 相对于只留一个值的 while( l<r ) 的写法,看起来是啰嗦了一点点,但是兼容性更高!
代码1:
//luogu1182:数列分段
//二分答案+贪心check
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0,l=0,r=0;
int a[100005];
bool ch(int x)//连续和是 x
{
int t=1,s=0;
for(int i=1;i<=n;i++)
{
if(s+a[i]<=x) s+=a[i];
else
{
s=a[i];
t++;
}
}
if(t<=m) return 1;//x还可以降低
return 0;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
l=max(l,a[i]);
r+=a[i];
}
while(l+1<r)//保留 l 和 r
{
int mid=(l+r)/2;
if(ch(mid)) r=mid;
else l=mid;
}
if(ch(l)) printf("%d",l);
else printf("%d",r);
return 0;
}