数列分段

来源:互联网 发布:数据丢失怎么恢复 编辑:程序博客网 时间:2024/05/16 12:56

问题描述

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

例如一数列 4 2 4 5 1 要分成 3 段 将其如下分段:
[4 2][4 5][1]
第一段和为 6,第 2 段和为 9,第 3 段和为 1,和最大值为 9。 将其如下分段:
[4][2 4][5 1]
第一段和为 4,第 2 段和为 6,第 3 段和为 6,和最大值为 6。 并且无论如何分段,最大值不会小于 6。

所以可以得到要将数列 4 2 4 5 1 要分成 3 段,每段和的最大值最小为 6。


输入文件

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


输出文件

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


样例输入

5 3
4 2 4 5 1


样例输出

6


数据规模与约定

对于 20%的数据,有 N≤10;
对于 40%的数据,有 N≤1000;
对于 100%的数据,有 N≤100000,M≤N, A[i]之和不超过 10^9。


分析

分为m段,每段连续,看起来貌似是一道DP的题目,但一看数据范围,就知道得要放弃。

这时注意到所有的A[i]只和不超过10^9,我们就可以二分答案,具体实现过程看代码


代码

#include <cstdio>#include <algorithm>using namespace std;int a[100002];int n,m;int read();int binary(int,int);int check(int);int main(){    freopen("divide_b.in","r",stdin);    freopen("divide_b.out","w",stdout);    n=read();    m=read();    for(int i=1;i<=n;++i)        a[i] = a[i-1]+read();    printf("%d",binary(0,a[n]));    return 0;}int read(){    int in = 0;    char ch = getchar();    while(ch<'0' || ch>'9')        ch = getchar();    while(ch>='0' && ch<='9'){        in = in*10+ch-'0';        ch = getchar();    }    return in;}int binary(int left,int right){    int mid;    while(left != right){        mid = check((left+right)>>1);        if(mid == -1)            left = ((left+right)>>1)+1;        else            if(left == mid)                return left;            else                right = mid;    }    return left;}int check(int t){    int r = -1;    int lst = 0;    int k = 1;    for(int i=1;i<=n&&k<=m;++i)        if(a[i]-a[lst] > t){            if(a[i-1]-a[lst] > r)                r = a[i-1]-a[lst];            lst = i-1;            if(a[i]-a[i-1] > t)                return -1;            k++;        }    if(a[n]-a[lst] > r)        r = a[n]-a[lst];    if(k <= m)        return r;    return -1;}
0 0
原创粉丝点击