题目大意
把N个数( ai )分成M份 (1≤ai≤10000,1≤N≤100000,1≤M≤N) ,每份得到一个和,问和的最大值的最小值是多少
分析
动态规划的方法是 O(N3) 的复杂度肯定超时。
根据经验,问最大值中的最小值问题有一部分和二分有关,,对于这道题,我们可以对答案进行二分(也叫二分答案),对于每一个答案去判断它是否满足要求,这道题就是判断是否存在一种分法中的最大值的最小值比当前答案小。
二分答案需要答案满足单调性,就是说如果当前答案满足要求,(这道题中)比这个答案大的也一定满足。
现在的问题是如何去判断一个答案是否满足要求,其实很简单,直接贪心从头开始取数,在不超过这个答案的前提下一直取数相加,一旦超过了则新建一份,最后的份数如果小于等于M则是符合要求。
这道题中和最大是 aiN=109 ,对于每次判断的花费是N,这样总的复杂度就是 Nlg(N∗104)
代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
int a[100005];
int n,m;
int maxa;//保存数组a中的最大值
bool Check(int k)//判断k是否满足要求
{
int sum=0;
int x=0;
for(int i=1;i<=n;i++)
{
if(a[i]>k)return 0;
if(sum+a[i]>k){x++;sum=a[i];}
else sum+=a[i];
}
if(sum!=0)x++;
if(x<=m)return 1;
else return 0;
}
void Work()
{
int L=maxa;
int R=maxa*n;
int M;
while(R>L)
{
M=(R+L)/2;
if(Check(M)==1)R=M;
else L=M+1;
}
cout<<L<<endl;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
maxa=0;
for(int i=1;i<=n;i++){scanf("%d",&a[i]);maxa=max(maxa,a[i]);}
Work();
}
return 0;
}