zoukankan      html  css  js  c++  java
  • 洛谷:P1182:数列分段`Section II`

    题目描述

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

    关于最大值最小:

    例如一数列 4 2 4 5 142451 要分成 33 段

    将其如下分段:

    [4 2][4 5][1][42][45][1]

    第一段和为 6 ,第 2 段和为 9 ,第 3 段和为 1 ,和最大值为 9 。

    将其如下分段:

    [4][2 4][5 1][4][24][51]

    第一段和为 4 ,第 2 段和为 6 ,第 3 段和为 6 ,和最大值为 6 。

    并且无论如何分段,最大值不会小于 66 。

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

    输入输出格式

    输入格式:

    第 1 行包含两个正整数N,M。

    第 22行包含 NN 个空格隔开的非负整数 Ai ,含义如题目所述。

    输出格式:

    一个正整数,即每段和最大值最小为多少。

    输入输出样例

    输入样例#1: 
    5 3
    4 2 4 5 1
    输出样例#1: 
    6

    说明

    对于 20\%20% 的数据,有 N≤10N10 ;

    对于 40\%40% 的数据,有 N≤1000N1000 ;

    对于 100\%100% 的数据,有 N≤100000,M≤N, Ai,Ai 之和不超过 10^9 。


      这个题时一个典型的二分答案(最大的最小、最小的最大)

      首先根据题意,我们确定段的最大值一定在整个数组的最大值和10^9之间,因此做如下定义

       l = maxn, r = 1000000000; 

      然后我们确定好一个mid = (l+r)>> 1,表示最大值为mid时是否可行;

      下面就进行二分的正常过程,判断

      然后遍历整个数列,记录下一个tot,表示这个数列中最大值不超过mid时,需要分成的段数,用now来代表当前段的和

      now+a[i]<mid时:可以继续加,这个段还没有结束

      now+a[i]==num时:说明当前段已经达到了最大值,记下这个段(tot++),now=0,以便分析下一个段

      now+a[i]>num时:说明这个段加上a[i]之后超过mid,就不能加上这个a[i],那么这个段已经计算完(tot++),a[i]算到下一个段内

      

      如果tot<m,说明要达到当前的段数m,mid的值必须要降低,这样才能使段数增多,收缩右边界;

      否则,改变左边界。

      

      附上代码(亲测AC)

     1 #include<iostream>
     2 #include<cmath>
     3 using namespace std;
     4 const int MAXN=100001;
     5 int maxn = -1;
     6 int n, m, a[1000010];
     7 int l = maxn, r = 1000000000;
     8 int judge(int num){
     9     int now = 0;
    10     int tot = 0;
    11     for(int i=1;i<=n;i++){
    12         if(now+a[i]<num){
    13             now += a[i];
    14         }
    15         else if(now+a[i]==num){
    16             now = 0;
    17             tot++;
    18         }
    19         else if(now+a[i]>num){
    20             now = a[i];
    21             tot++;
    22         }
    23     }
    24     if(now) tot++;  //如果还有剩余的一个值,那么这个单独算一个段
    25     if(tot>m)return 0;
    26     else return 1;
    27     
    28 }
    29 
    30 int main(){
    31     cin >> n >> m;
    32     for(int i=1;i<=n;i++) {
    33         cin >> a[i];
    34         maxn = max(a[i], maxn);
    35     }
    36     int l = maxn, r = 1000000000;     
    37     if(n==m){
    38         cout << maxn;
    39         return 0;
    40     }
    41     while(l<r){
    42         int mid = (l+r) >> 1;
    43         if(judge(mid)==1){
    44             r = mid;
    45         }
    46         else{
    47             l = mid + 1;
    48         }
    49     }
    50     cout << r;
    51     return 0;
    52 } 
  • 相关阅读:
    经典句子与段落点滴记录
    人生成功的六匹马(转自喷嚏网的一篇品书)
    Android 时间 更新与同步
    Camera driver&V4L2驱动架构介绍
    SimpleApp例子中网络的形成过程(转)
    Zigbee之旅(十):综合小实验——基于CC2430的温度监测系统(转)
    ZStack协议中命令的概念(转)
    Zigbee之旅(八):几个重要的CC2430基础实验——看门狗(转)
    Zigbee之旅(七):几个重要的CC2430基础实验——DMA传输(转)
    Zigbee之旅(六):几个重要的CC2430基础实验——ADC单次采样(转)
  • 原文地址:https://www.cnblogs.com/jyroy/p/9433629.html
Copyright © 2011-2022 走看看