数列分段

题目描述

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

输入格式

输入文件divide_b.in的第1行包含两个正整数N,M,第2行包含N个空格隔开的非负整数A[i],含义如题目所述。

输出格式

输出文件divide_b.out仅包含一个正整数,即每段和最大值最小为多少。

样例输入

5 3

4 2 4 5 1

样例输出

6

【题目 https://www.luogu.org/problemnew/show/1182】(蒟蒻不会弄链接,望大佬指点orz)

题解

“最大值最小”,二分的标志

二分最大值mid,检查时枚举每个数要放入已有的段还是另起一段,如果一个数放入已有段后,该段和不超过mid,那么放进去,否则另起一段,同时计数器加1.
最后把计数器和M比较,如果不比M大,说明当前mid值足够大,可以小一点,于是r=mid-1;否则说明当前mid值偏小,要大一点,于是l=mid+1。

计数器初始值为1,因为数列至少会被分成一段,(我第一次把计数器初始为0,样例过了,交上去居然全WA了(ㄒ _ ㄒ))

#include <cstdio>
int n,m,a[100005],l,r,mid,ans;
bool check()
{
    int s=1,sum=0;
    for (int i=1;i<=n;i++)
      if (sum+a[i]<=mid) sum+=a[i];
      else s++,sum=a[i];  
    return (s<=m);  
}
int main()
{
    int i;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        r+=a[i];
        if (a[i]>l) l=a[i];
    }
      
    while (l<=r)
    {
        mid=(l+r)>>1;
        if (check()) r=mid-1,ans=mid;
        else l=mid+1;
    }  
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/rabbit1103/p/7786946.html