BZOJ【1639】: [Usaco2007 Mar]Monthly Expense 月度开支

1639: [Usaco2007 Mar]Monthly Expense 月度开支

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 700  Solved: 347
[Submit][Status][Discuss]

Description

Farmer John是一个令人惊讶的会计学天才,他已经明白了他可能会花光他的钱,这些钱本来是要维持农场每个月的正常运转的。他已经计算了他以后N(1<=N<=100,000)个工作日中每一天的花费moneyi(1<=moneyi<=10,000),他想要为他连续的M(1<=M<=N)个被叫做“清算月”的结帐时期做一个预算,每一个“清算月”包含一个工作日或更多连续的工作日,每一个工作日都仅被包含在一个“清算月”当中。 FJ的目标是安排这些“清算月”,使得每个清算月的花费中最大的那个花费达到最小,从而来决定他的月度支出限制。

Input

第一行:两个用空格隔开的整数:N和M

第2..N+1行:第i+1行包含FJ在他的第i个工作日的花费

Output

第一行:能够维持每个月农场正常运转的钱数

 

Sample Input

7 5
100
400
300
100
500
101
400

Sample Output

500
题解:
第一眼看到这道题我竟然想到了贪心(吓得我赶紧上了个厕所冷静一下
这道题其实就是二分,因为数据限制m,n均为10000,所以最大值不会大于100000000,所以mid=(1+100000000)>>1;
接着把每天的费用依次加起来,如果sum>mid的话,那么需要在增加一个月份,所以tot++;否则无脑加加即可
每次判断最后都需要进行特判,如果a[i]>mid||tot>m,则说明所要查询的值一定在mid右边,反之则在mid左边。
但要注意tot初始化要为1.
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<cstdlib>
 7 #define maxn 100000+100
 8 int a[maxn],n,m,ans;
 9 bool pan(int q)
10 {
11     int sum=0,tot=1; //切记tot=1;
12     for(int i=1;i<=n;++i)
13     {
14         if(sum+a[i]<=q) sum+=a[i];
15         else
16         {
17             sum=a[i];++tot;
18         }
19         if(tot>m||a[i]>q) return 0;
20     }
21     return 1;
22 }
23 int erfen(int p)
24 {
25     int l=1,r=100000000;
26     while(l<=r)
27     {
28         int mid=(l+r)>>1;
29         if(pan(mid)) {
30             ans=mid;r=mid-1;
31         }
32         else l=mid+1;
33     }
34     return ans;
35 }
36 using namespace std;
37 int main()
38 {
39     freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
40     cin>>n>>m;
41     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
42     erfen(n);
43     cout<<ans; 
44     return 0;
45 }
View Code

 

posted @ 2015-10-03 01:09  Maydaytyh  阅读(221)  评论(0编辑  收藏  举报