洛谷 P1182 数列分段 题解

题面

给大家普及一个知识,只要看到最大值最小或最小值最大等字样就往二分上想吧!

然后是正解部分:
   我们可以二分答案;
   对于每次二分的区间取中间值mid,并对其进行check()判断;
   如果所有段的最大值为mid时可以分成m段(注意,如果此时分成的段比m还小,那么也是可行的,因为你可以随便拆拆就能拆成m段,但显然可能不是最优的解),那么我们就将二分区间更改为(l,mid),因为(mid+1,r)区间所有的答案均可行且都不是最优的。否则将区间改为(mid+1,r);
   
 另外说明一下,二分的退出条件是l==r,并记录ans等于此时的r。
 然后输出ans就好了

#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[100010],sum[100010];
int ans;
bool check(int x)
{
    for(int i=1;i<=n;i++){
        if(sum[i]-sum[i-1]>x){
            return 0;
        }
    }
    int tmp=0;
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(sum[i]-tmp>x){
            tmp=sum[i-1];
            ++cnt;
            i--;
        }
    }
    if(cnt+1>m)  return 0;
    return 1;
}
void erfen(int l,int r)
{
    if(l==r){
        ans=l;
        return;
    }
    int mid=(l+r)/2;
    if(check(mid)) erfen(l,mid);
    else erfen(mid+1,r);
}
int main ()
{    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    erfen(1,sum[n]);
    cout<<ans;
}
原文地址:https://www.cnblogs.com/kamimxr/p/11319249.html