http://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1919

 

Description

晴天想把一个包含n个整数的序列a分成连续的若干段,且和最大的一段的值最小,但他有强迫症,分的段数不能超过m段,然后他就不会分了。。。他想问你这个分出来的和最大的一段的和最小值是多少?

Input

第一行输入一个整数t,代表有t组测试数据。
每组数据第一行为两个整数n,m分别代表序列的长度和最多可分的段数。
接下来一行包含n个整数表示序列。
0<=n<=50000 1<=m<=n,0<=ai<=10000。

Output

输出一个整数表示和最大的一段的最小值。

Sample Input

1 3 2 1 3 5

Sample Output

5

HINT

 

1 3 5 分成一段可以为1 3 5和为9,分成两段可以为1,3 5或者1 3,5,和最大的一段值分别为8,5,所以答案为5

 
 
 
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <stack>
#include <math.h>

using namespace std;

#define INF 0x3f3f3f3f
const int maxn = 61000;
typedef long long LL;
int a[maxn];
int n, m;

int Judge(int sum)
{
    int ans = 0;
    int cnt = 0;

    for(int i=1; i<=n; i++)
    {
        if(ans+a[i]>sum)///判断以sum为一段的最大值 能有几段
        {
            ans=a[i];
            cnt++;
            if(cnt>=m) return 0;///如果超过m段,则返回0
        }
        else
            ans+=a[i];
    }

    return 1;
}

int main()
{
    int T;

    scanf("%d", &T);

    while(T --)
    {
        scanf("%d %d", &n, &m);

        int maxs = 0;
        int sum = 0;
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            maxs=max(maxs, a[i]);
            sum += a[i];
        }

        int l=maxs;
        int r=sum;
        int ans;

        while(l<=r)///所求值一定在maxs和sum之间,从中选出最小的
        {
            int mid=(l+r)/2;

            if(Judge(mid))///若mid满足分m段最大值为mid,则缩小r,判断是否还有最优解
            {
                ans = mid;
                r = mid-1;
            }
            else
                l=mid+1;///若不满足,则加大l的值
        }

        printf("%d\n", ans);
    }
    return 0;
}
View Code

 

posted on 2016-08-19 17:35  不忧尘世不忧心  阅读(163)  评论(0编辑  收藏  举报