您的位置:首页 > 其它

数列分段

2016-01-28 16:37 323 查看

问题描述

对于给定的一个长度为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,我们就可以二分答案,具体实现过程看代码

代码

[code]#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
));

    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
-a[lst] > r)
        r = a
-a[lst];

    if(k <= m)
        return r;
    return -1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: