洛谷P1182 数列分段`Section II`

题目描述

对于给定的一个长度为N的正整数数列 A-iA−i ,现要将其分成 M(M≤N)M(M≤N) 段,并要求每段连续,且每段和的最大值最小。

关于最大值最小:

例如一数列 4 2 4 5 142451 要分成 33 段

将其如下分段:

[4 2][4 5][1][42][45][1]

第一段和为 66 ,第 22 段和为 99 ,第 33 段和为 11 ,和最大值为 99 。

将其如下分段:

[4][2 4][5 1][4][24][51]

第一段和为 44 ,第 22 段和为 66 ,第 33 段和为 66 ,和最大值为 66 。

并且无论如何分段,最大值不会小于 66 。

所以可以得到要将数列 4 2 4 5 142451 要分成 33 段,每段和的最大值最小为 66 。

输入输出格式

输入格式:

第 11 行包含两个正整数N,M。

第 22 行包含 NN 个空格隔开的非负整数 A_iAi​ ,含义如题目所述。

输出格式:

一个正整数,即每段和最大值最小为多少。

输入输出样例

输入样例#1

5 3
4 2 4 5 1

输出样例#1

6

说明

对于 20\%20% 的数据,有 N≤10N≤10 ;

对于 40\%40% 的数据,有 N≤1000N≤1000 ;

对于 100\%100% 的数据,有 N≤100000,M≤N, A_iN≤100000,M≤N,Ai​ 之和不超过 10^9109 。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
int n,a[100005];
int ans,x,m,maxn;
int num,sum;
int work(int x)
{
	int cnt=1;
	int wzx=0;
	for(int i=1;i<=n;i++)
	{
		wzx+=a[i];
		if(wzx>x)
		{
			wzx=a[i];
			cnt++;
			continue;
		}
	}
	if(cnt<=m)
	return 1;
	else
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		
		scanf("%d",&a[i]);
		maxn=max(maxn,a[i]);
		ans=ans+a[i];
	}
	int l=maxn;
	int r=ans;
	while(l<=r)
	{
	  int mid=(l+r)>>1;
	  if(work(mid))
	  r=mid-1;
	  else
	  l=mid+1;
	}
	cout<<l<<endl;
}

猜你喜欢

转载自blog.csdn.net/wzx1078132012/article/details/81297351