[关闭]
@Aonrbet 2018-10-31T10:02:50.000000Z 字数 1401 阅读 1111

P2440木材加工

题解 OI笔记


题目链接

最最最最基本的二分题!

Noip2018之前做道二分题,万一考到了呢?(望我这篇题解对想了解二分的人有帮助)

话归正传:

咳,这是一道十分基本的二分答案,可以当做模板来用

二分基本做法:

设置一个左端点和右端点,为中间值,如果比中间值小,则右端点转为,否则左端点转为

很容易想到到,只要我们不断地二分下去,正确答案迟早会得到的。

这里提供一种二分模板(仅供参考,二分有好多种写法的)

  1. int l = 0 , r = 210000000 ;
  2. while( l < r - 1 ){ //这里要注意一下,l必须要<r-1,否则会陷入死循环
  3. int mid = l + r >> 1 ;
  4. if( mid >= flag ) r = mid ;
  5. else l = mid ;
  6. }

为什么 ?

我们可以手动模拟一下:

1.我们假设 ; 那么
2.再来一次,

很明显,对于在第二步之后,一直小于,并且的值在第二步之后一直未发生改变,这样我们就会陷入死循环,所以我们需要,在第一步时我们就已经得到正确答案,那时,不满足循环条件,跳出,即为正确答案.

另一种写法:

  1. while( l <= r ){
  2. int mid = l + r >> 1 ;
  3. if( mid >= flag ){
  4. ans = mid ;
  5. r = mid - 1 ;
  6. }
  7. else l = mid + 1 ;
  8. }

这里使用各加一或减一来避免死循环,要注意的是这里用来储存答案,因为对应的值有所改变

问题来了,那么对于这道题我们应该怎么去做呢?

首先题目给了我们一个要求截成的段,那么我们可以去二分这个,首先我们的要满足之和要等于,如果大于,则表明我们的取值小了,,否则(PS:这里与上面的板子有所不同,其实的转换是应该根据实际情况去判断的)

于是二分思想有了,接下来我们去找端点

端点这个问题也是值得我们注意的,首先题目上表明木材可以剩余和丢弃,那么假如我们有一段木头贼长,仅凭他一己之力就可以去截出最长且满足段,那么我们其他的全可以丢弃,就截这一段就可以了(这是一个坑点,这个题的数据点3完美的坑到了我),于是我们的端点初始并不是木材中的最大值,而应设为一个极大的数,只要超过题目中木材长度最大就好了。

emmm,还有判断函数,其实就要把加起来,再返回回去就好啦(详细见附码)

于是我们有了端点、二分思想、判断函数、还有板子,便可以愉快的AC啦~~qwq

附code:

  1. #include <cstdio>
  2. int n , k , a[100500] ;
  3. int judge( int temp ){
  4. int sum = 0 ;
  5. for( int i = 1 ; i <= n ; i ++ ) sum += a[i] / temp ;
  6. return sum ;
  7. }
  8. int main(){
  9. scanf( "%d%d" , &n , &k ) ;
  10. for( int i = 1 ; i <= n ; i ++ ){
  11. scanf( "%d" , &a[i] ) ;
  12. }
  13. int l = 0 , r = 210000000 ;
  14. while( l < r - 1 ){
  15. int mid = ( l + r ) >> 1 ;
  16. if( judge( mid ) >= k ) l = mid ;
  17. else r = mid ;
  18. }
  19. printf( "%d" , l ) ;
  20. return 0 ;
  21. }

趁热打铁

看到代码觉得很简单的有木有?

我突然觉得这道题是伪普及

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注