BZOJ【1639】: [Usaco2007 Mar]Monthly Expense 月度开支
1639: [Usaco2007 Mar]Monthly Expense 月度开支
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 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
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.
View Code
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 }