luogu1182:数列分段:二分答案+贪心查找

题目连接

  • 该题是luogu试炼场的2-12:T6

题目大意

  1. 给出 n 个数字,分成 m 段;
  2. 每一段的和 s,要求 s 的最大值尽可能小。

题目分析


解题思路:

  1. 初始的左边界L:一定是数组的最大值,因为最小的值,也必须有一个数字在里面;
  2. 初始的左边界R:是数组的和,因为可能m的值是1,全部人都在同一组;
  3. 二分的while()循环,看起来没有难度,但是结束条件才是精髓:本题解用的是 while( l+1<r) ,在执行完二分之后,并不是得到一个值,而是得到 l 和 r 两个值,最后特判一下;
  4. 相对于只留一个值的 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; 
}







猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/89472782