题目链接:数列分段 Section II
题目描述:给定一个长度为N的数列,现在要将其分为M段(M<=N),分段要求连续的对数列进行分段,并且每段和的最大值最小。
例如:对42451要分为3段。
则将其进行如下分段:
[4][24][51]或[42][4][51]
最大值为6;
解决思路:
采用二分查找的方法,逐个查找最小的最大值。
首先先确定最大值的范围(大于等于数列中最大的数,小于等于数列中数的总和),然后分别用 left(数列中最大的数),right(数列中数的总和)表示两个边界。
每次求出中值mid=(left+rght)/2; 再将中值作为最大值对数列进行分段,得出的段数与题目要求的段数进行比较,如果大于或等于M就说明需要将 right 进一步缩小(right=mid-1)再进行查找,小于M的话就需要将left增大(left=mid+1)再进行查找,直到循环结束(也就是 left>right)。
最后left就是我们要求的最小的最大值。
代码:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
ll n,m;
ll a[100005];
ll r=0;
ll l=0;
ll p(ll m){
ll t=0;
ll k=0;
for(int i=1;i<=n;i++){
if(t+a[i]<=m){
t+=a[i];
}
else{
t=a[i];
k++;
}
}
return k;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
r+=a[i];
if(a[i]>l){
l=a[i];
}
}
while(l<=r){
ll mid=(l+r)/2;
ll k=p(mid);
if(k>=m){
l=mid+1;
}
else{
r=mid-1;
}
}
cout<<l<<endl;
return 0;
}