二分法的习题

  • Post author:
  • Post category:其他


1.


1.1题目分析:

1.1.1题干分析:

输出结果:能量E

输出范围:[1,1e5]

当h>E    E = E – (h – E) = 2E – h

当h<=E  E = E + E – h = 2E – h

无论h与E的大小关系,都有


E = 2E – h

1.1.2.方法选用分析:



求最大最小问题


,依次考虑


二分




dfs



Dp



贪心




二分要考虑结果是否有



二段性







单调性





二段性:



能量



E



= mid 时 , 能否使E保持大于零



单调性

:E_k成立时, E_k+1也成立

可以采用二分法解题

1.1.3.方法结题分析:

边界:L = 0 , R = 1e5

判断条件 :能量E能否跳过,即为E始终大于0

当E = mid 可以跳过 , 则最小值在左侧,所以

R=mid

,则

mid = (l+r)>> 1

当E = mid 不能跳过 , 则最小值在右侧,且最小值不是mid,则

L = mid +1

​​

1.2程序设计:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 100010 ;
int n;
int h[N];

//判断E能否跳过
bool check(int e){ 
    bool fleg = true ;
    for(int i=1;i<=n;i++)
    {
        e = 2*e - h[i] ;       //能量表达式
        if(e>=1e5) {           //能量大于边界,肯定能跳过。防止爆掉,break结束循环
            fleg = true;
            break;
        }
        if(e<0) {              //能量跳不过
            fleg=false;
            break;
        }
    } 
    return fleg ;
}

int main(){
    scanf("%d",&n);                                 //读取楼个数
    for(int i=1;i<=n;i++)  scanf("%d",&h[i]);       //读取楼高度
    
    //二分法
    int l =0 ,r= 1e5;                               //左右区间
    while(l<r)                                      //循环条件
    {
        int mid = (l+r)>>1;                         //二分
        if(check(mid)) r = mid ;                    //判断条件
        else l = mid + 1 ;
    }
    printf("%d\n",r);                               //输出结果
    return 0;
}

2.

2.1题目分析:

2.1.1.题干分析:

输出结果:切分正方形巧克力的边长

输出范围:[1,1e5]



分巧克力只能切割,不能拼接!!!

一块边长为H[i] 和 K[i] 的巧克力,分为边长为z的正方形,可分


( H[i] / z ) * ( K[i] / z )


块(向下取整)。

2.1.2.方法选用分析:



求最大最小问题


,依次考虑


二分




dfs



Dp



贪心




二分要考虑结果是否有



二段性







单调性



单调性

:边长为z的正方形成立时, z-1 的正方形也成立





二段性:



边长 z






= mid ,判断能否成立

可以采用二分法解题

2.1.3.方法结题分析:

边界:L = 1 (至少分成1 * 1的巧克力) , R = 1e5

判断条件 :按照边长为z的正方形切割得到的块数sum能否大于小朋友个数

当 z = mid 成立 , 则最大值在右侧,所以

L


= mid

,则

mid =(l + r + 1 )>> 1

当 z = mid 不成立 , 则最大值在左侧,且最大值不是mid,则

R = mid -1

​​​​​​​​​

2.2.程序设计:

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 100010;
int n, f ;                   //n:巧克力个数 f:小朋友个数
int H[N], W[N] ;             //巧克力边长H[N],W[N]
int z ;                      //正方形边长

bool check(int z)
{
    int sum=0 ; 
    for(int i=0;i<n;i++)
    {
        sum = sum + ( H[i] / z ) * ( W[i] / z ) ;  //分巧克力块数
        if(sum >= f) return true;                  //足够分给f个小朋友
    }
    return false;
}

int main()
{
    scanf("%d %d",&n,&f);                              //读取n块巧克力 ,f个小朋友
    for(int i=0;i<n;i++)  scanf("%d %d",&H[i],&W[i]);  //n块巧克力的边长H和W
    
    //二分
    int mid;
    int l = 1 , r = N ;             
    while(l < r)
    {
        mid = l + r + 1 >> 1;
        if(check(mid)) l = mid ;
        else r = mid - 1 ;
    }
    printf("%d\n",r);
    return 0;
}

3.

3.1题目分析:

3.1.1.题干分析:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>

using namespace std ;

const int N = 2500010;

struct Sum {
    int s, c, d;
    bool operator< (const Sum &t) const
    {
        if(s != t.s) return s < t.s;
        if(c != t.s) return c < t.c;
        return d < t.d;
    }
}sum[N];

int n , m;

int main()
{
    cin >> n ;
    for(int c = 0; c*c <=n; c++){
        for(int d=c; c*c + d*d <=n; d++)  
            sum[m ++] = {c*d + d*d,c,d};
    }
    sort(sum,sum + m);   //排序
    
    for(int a=0; a*a<=n ; a++){
        for(int b=a; a*a + b*b <= n;b++)
        {
            int t = n - a*a - b*b ;
            //二分
            int l =0 ,r =m-1;
            while(l<r)
            {
                int mid= l+r >> 1;
                if(sum[mid].s >= t) r=mid;
                else l = mid+1;
            }
            if(sum[l].s == t)
            {
                printf("%d %d %d %d\n", a, b, sum[l].c, sum[l].d);
                return 0;
            }
        }
    }
    return 0;
}



版权声明:本文为weixin_62802580原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。