分段求和 - 题目 - Daimayuan Online Judge
题意:
对于给定的一个长度为 N 的正整数数列A1−N,现要将其分成 M(M≤N) 段,并要求每段连续,且每段和的最大值最小,输出每段和最大值最小为多少。
思路:
看到最大值最小,就想到二分
我们把每段和最大值二分出来即可
那么怎么check?
在二分里贪心是个非常常见的思路,我们维护双指针l和r,每当超过二分出来的值的时候,r--之后区间[l,r]就是一个段。为什么要快超过二分出来的值的区间作为一个段,因为这样操作过去操作到数列最后,如果发现段的数量>m,就说明我们取段之和最大的情况都不够分段,段之和更小的时候就一定不够分段,所以return false。但是如果段的数量<=m,说明只需要把前面分的段再细分一点就能使得段数等于m,因此这种情况return true
Code:
#include <bits/stdc++.h>
using namespace std;
const int mxn=1e5+10;
#define int long long
int n,m,ans;
int a[mxn],s[mxn];
bool check(int x){
int l=1,r=1,cnt=0;
while(1){
while(s[r]-s[l-1]<=x&&r<=n) r++;
cnt++;
if(cnt>m) return false;
if(r>n) break;
l=r;
}
if(cnt<=n) return true;
return false;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),s[i]=s[i-1]+a[i];
int l=1,r=1e9;
while(l<=r){
int mid=l+r>>1;
if(check(mid)){
ans=mid;
r=mid-1;
}else l=mid+1;
}
printf("%lld\n",ans);
}
总结:简单二分