06:月度开销
2016-06-22 18:29
134 查看
题目链接:http://noi.openjudge.cn/ch0111/06/
总时间限制: 1000ms 内存限制: 65536kB
描述
农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来 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
输入输出样例说明
若约翰将前两天作为一个月,第三、四两天作为一个月,最后三天各自作为一个月,则最大月度开销为500。其他任何分配方案都会比这个值更大。
先看AC代码:
思路说明:
题目的意思一定要理解清楚!!!“合理安排每个fajo月包含的天数,使得开销最多的fajo月的开销尽可能少。” “输出一个整数,即最大月度开销的最小值。”
就是把所有天划分为若干个段,先求出每个段里面的数字之和,然后统计各段累加和的最大值,这个值要尽可能小。现在要找的就是这个“累加和的最大值” 最小可以是多少。
首先,这个题目应该二分,因为解的区间是可以明确的,可以对该区间进行二分求的真正的解。
假设二分的区间left~right,其中left是n天开销中最大的那一个数字,right是n天开销的总和。 (设想一个极限情况,要使得每一个月开销尽量小,那么每一天都单独做一个月就好啦,于是这个时候的月开销最大值就是n天中每天开销最大的值,所以left可以取max(a1,......,an)。 再设想另一种极限情况,把所有天合并在一起组成一个月,那么这个时候月开销最大值就是sum(a1,a2,......,an),所以right取值就是n天的累加和。)
需要注意的一个地方是二分循环部分的代码:
其中left=mid+1这里必须加上1,否则可能会死循环的。
另外,输出值是left。这个地方也要特别注意。(请自己脑补为何是left吧)
关于子函数check(),嗯代码注释讲的很清晰,不说了。
总时间限制: 1000ms 内存限制: 65536kB
描述
农夫约翰是一个精明的会计师。他意识到自己可能没有足够的钱来维持农场的运转了。他计算出并记录下了接下来 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
输入输出样例说明
若约翰将前两天作为一个月,第三、四两天作为一个月,最后三天各自作为一个月,则最大月度开销为500。其他任何分配方案都会比这个值更大。
先看AC代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> int check(long *a,long N,long long mid,long M); int main() { long N,M; long *a=NULL,i; long long left=0,right=0,mid=0; int res; scanf("%ld%ld",&N,&M); a=(long*)malloc(N*sizeof(long)); memset(a,0,N); for(i=0;i<N;i++) { scanf("%ld",&a[i]); if(a[i]>left) left=a[i]; right=right+a[i]; } while(left<right) { mid=left+(right-left)/2; res=check(a,N,mid,M); if(res==1) right=mid; else left=mid+1; } printf("%lld\n",left); return 0; } //假设最大月开销为mid,统计需要分成多少个月.然后看月的个数是否太多或太少 int check(long *a,long N,long long mid,long M) { long count=1,i,temp=0; for(i=0;i<N;i++) { if(temp+a[i]<=mid) temp=temp+a[i];//把第i天归入到当前第count月 else if(a[i]<=mid)//可以独立成一个月 { count++;//开始一个新的月 temp=a[i]; if(count>M) return -1;//最大月开销太小,导致分的组太多了。 } else return -1;//最大月开销mid太小了,导致某些开销比较大的天单独构成一个月都不行。 } if(count>M) return -1; else if(count<=M) return 1;//最大月开销mid太大了,导致分的组太少了 }
思路说明:
题目的意思一定要理解清楚!!!“合理安排每个fajo月包含的天数,使得开销最多的fajo月的开销尽可能少。” “输出一个整数,即最大月度开销的最小值。”
就是把所有天划分为若干个段,先求出每个段里面的数字之和,然后统计各段累加和的最大值,这个值要尽可能小。现在要找的就是这个“累加和的最大值” 最小可以是多少。
首先,这个题目应该二分,因为解的区间是可以明确的,可以对该区间进行二分求的真正的解。
假设二分的区间left~right,其中left是n天开销中最大的那一个数字,right是n天开销的总和。 (设想一个极限情况,要使得每一个月开销尽量小,那么每一天都单独做一个月就好啦,于是这个时候的月开销最大值就是n天中每天开销最大的值,所以left可以取max(a1,......,an)。 再设想另一种极限情况,把所有天合并在一起组成一个月,那么这个时候月开销最大值就是sum(a1,a2,......,an),所以right取值就是n天的累加和。)
需要注意的一个地方是二分循环部分的代码:
while(left<right) { mid=left+(right-left)/2; res=check(a,N,mid,M); if(res==1) right=mid; else left=mid+1; } printf("%lld\n",left);
其中left=mid+1这里必须加上1,否则可能会死循环的。
另外,输出值是left。这个地方也要特别注意。(请自己脑补为何是left吧)
关于子函数check(),嗯代码注释讲的很清晰,不说了。
相关文章推荐
- mysql主从复制
- 报错,未知错误1
- iOS开发:UIImageView常用操作
- Eclispe添加本地Struts2的DTD文件
- Git的使用
- 锁存器和自旋锁(Latch&Spinlock)----理解Latch和Spinlock
- ios -- NSNotification(通知)
- 使用GCDAsyncUdpSocket&GCDAsyncSocket进行TCP连接和UDP连接
- 框架模式MVC与MVP在Android中的应用
- 所谓的牛逼,都是用苦逼换来的
- 10-4-表插入排序-内部排序-第10章-《数据结构》课本源码-严蔚敏吴伟民版
- 【IOS开发】UIImageView的用法。。图片
- Activiti工作流之异常处理一
- Apache Flink流分区器剖析
- Ionic实战五:ionic图表源码基于highcharts
- Linux 管理FTP 服务
- fork()函数
- plsql 连接oracle数据库详细配置
- 《OD学算法》排序
- 详解ABP框架中领域层的领域事件Domain events