【动规】【二分】【120814测试】【NOIP第二次模拟赛】划分数列

2.划分数列(seq.pas/c/cpp)

【题目描述】

给你一个有n个元素的数列,要求把它划分成k段,使每段元素和的最大值最小

【输入格式】

第一行两个正整数n,k

第二行为此数列ai

【输出格式】

一行一个数,为题目所求答案

【样例输入】

5 2

2 1 3 4 5

【样例输出】

9

【数据规模】

30%数据 n <= 30, k <= 10

100%数据 n <= 100000, k <= n, ai <= 10^9

【时限】

1s

 

前面已经说了,如果只用动规,是O(n3)的时间复杂度,只能拿50分

而看到这种求最大值最小,或者最小值最大的题(类似关押罪犯)就应该想到去二分答案,就能拿100分

C++ Code

#include<cstdio>
#include<string>
using namespace std;
#define MAXN 100000+10

int n,m,a[MAXN],sum;

bool ok(int mm)
{
    int num=0,s=0,i=0;
    while(true)
    {
        s=0;
        while(true)
        {
            if(i>=n){num++;break;}
            if(s+a[i+1]<=mm)
            {
                s+=a[i+1];
                i++;
            }
            else if(s+a[i+1]>mm){num++;break;}
        }
        //printf("s=%d  i=%d   num=%d\n",s,i,num);
        if(i>=n)break;
    }
    if(num<=m)return true;else return false;
}

int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    scanf("%d%d",&n,&m);
    int i;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum+=a[i];
    }
    int l=1,r=sum,mid;
    while(l<r)
    {
        mid=l+(r-l)/2;
        //printf("l=%d r=%d mid=%d\n",l,r,mid);
        if(ok(mid))r=mid;else l=mid+1;
    }
    printf("%d",r);
}

 

 

 

posted @ 2012-08-20 19:45  jiangzh  阅读(396)  评论(0编辑  收藏  举报