青少年编程知识记录 codecoming

【题解】月度开销

【题目描述】

农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来N(1 ≤N≤ 100,000) 天里每天需要的开销。

约翰打算为连续的M(1 ≤M≤N) 个财政周期创建预算案,他把一个财政周期命名为fajo月。每个fajo月包含一天或连续的多天,每天被恰好包含在一个fajo月里。

约翰的目标是合理安排每个fajo月包含的天数,使得开销最多的fajo月的开销尽可能少。

【输入描述】

第一行包含两个整数N,M,用单个空格隔开。

接下来N行,每行包含一个1到10000之间的整数,按顺序给出接下来N天里每天的开销。

【输出描述】

一个整数,即最大月度开销的最小值。

【样例输入】

7 5  100  400  300  100  500  101  400

【样例输出】

500

【题目分析】

  • 题目描述的过于复杂,实际上就是二分,N是天数,M是要分成的财政周期。

  • 区别:月度开销的值应该在 每天开销最大值 和 每天开销的总和 之间,通过二分法不断逼近。judge函数判断按照mid开销所分的周期,如果周期大于给定周期M,则可以增加开销,反之,减小开销。



【参考代码】

#include<iostream>  #include<cstdio>  #include<cstdlib>  #include<cstring>  #include<cmath>  #include<algorithm>  #include<string>  #define INF 999999999  #define N 1000001  #define MOD 1000000007  #define E 1e-3  using namespace std;  int n,m,a[N];  int judge(int x)  {      int money=0,month=0,d,i;      for(i=1;i<=n;i++)      {          money+=a[i];          if(money>=x)          {              month++;              if(a[i]<x)                  money=a[i];              else                  return 1;          }      }      return month>=m;  }  int main()  {      int left,right,mid;      int tot=0;      cin>>n>>m;      for(int i=1;i<=n;i++)      {          cin>>a[i];          tot+=a[i];      }      left=1;      right=tot;      while(left+1<right)      {          mid=(left+right)/2;          if(judge(mid))              left=mid;          else              right=mid;      }      if(judge(left))          cout<<left<<endl;      else          cout<<right<<endl;      return 0;  }



(adsbygoogle = window.adsbygoogle || []).push({});