二分大体总结

二分

二分的题目由于其方式的特殊性,一般能够二分出来的结果基本上是不会发生超时情况,但是我们需要注意的是二分的对象问题,就是我们应该对什么东西来进行二分。这是我们理解分析二分题目的重中之重。

P1873 砍树

这个题应该算是二分当中比较基础的一道题目,非常简单,我们二分的目标主要就是答案,我们需要砍树的高度就是我们需要去求得的结果,然而这个结果有一个区间,区间显然是0 ——这群树的最高高度。
然后通过二分答案区间组来快速求得答案。

P1024 一元三次方程求解

这道题也应该算是比较经典的一道题目,我们需要通过二分定义答案区间,这个题需要注意的是二分时while循环的条件

P1182 数列分段 Section II

这个题目很有意思,我们二分的是我们所需要的答案,但是我们需要将我们求得答案的区间进行压缩,右区间显然是全部数值相加的和,左区间应该是我们的全部数组中每个元素的最大值.然后通过二分求得该答案是否可行。二分的时候在check函数里面,我们可以定义一个数,来对每一个已经达到我们测试的值进行分装。

P1577 切绳子

本题需要注意的基本点与前面三个结合起来比较像

下面附上ac代码

砍树

伐木工人米尔科需要砍倒M米长的木材。这是一个对米尔科来说很容易的工作,因为他有一个漂亮的新伐木机,可以像野火一样砍倒森林。不过,米尔科只被允许砍倒单行树木。

米尔科的伐木机工作过程如下:米尔科设置一个高度参数H(米),伐木机升起一个巨大的锯片到高度H,并锯掉所有的树比H高的部分(当然,树木不高于H米的部分保持不变)。米尔科就行到树木被锯下的部分。

例如,如果一行树的高度分别为20,15,10和17,米尔科把锯片升到15米的高度,切割后树木剩下的高度将是15,15,10和15,而米尔科将从第1棵树得到5米,从第4棵树得到2米,共得到7米木材。

米尔科非常关注生态保护,所以他不会砍掉过多的木材。这正是他为什么尽可能高地设定伐木机锯片的原因。帮助米尔科找到伐木机锯片的最大的整数高度H,使得他能得到木材至少为M米。换句话说,如果再升高1米,则他将得不到M米木材。

输入格式
第1行:2个整数N和M,N表示树木的数量(1<=N<=1000000),M表示需要的木材总长度(1<=M<=2000000000)

第2行:N个整数表示每棵树的高度,值均不超过1000000000。所有木材长度之和大于M,因此必有解。

输出格式
第1行:1个整数,表示砍树的最高高度。

样例输入:
5 20
4 42 40 26 46
样例输出:
36

AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1000010;
int q[N];
int n;
long long m;
bool check(int x)
{
    long long sum = 0;
    for(int i = n; q[i] > x && i >= 1; i --)    sum += q[i] - x;
    if(sum >= m) return true;
    else return false;
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ )   cin >> q[i];
     
    sort(q + 1, q + 1 + n);
    
    int l = 0, r = q[n], mid;
    while(l < r)
    {
        mid = (l + r + 1) / 2;
        if(check(mid))  l = mid;
        else r = mid - 1;
    }
    cout << r;
    return 0;
}

一元三次方程求解

ax^3 + bx^2 + cx + d;

输入格式
一行,4个实数A,B,C,D

输出格式
一行,3个实根,并精确到小数点后2位。

样例输入:
1 -5 -4 20
样例输出:
-2.00 2.00 5.00

AC代码:

#include<iostream>
#include<stdio.h>
using namespace std;
float a, b, c, d, mid;
float res(float x)//
{
    float q;
    q = a * x * x * x + b * x * x + c * x + d;
    return q;
}
int main()
{
    cin >> a >> b >> c >> d;
    for(float l = -100; l <= 99; l ++)
    {
        float r = l + 1;
        if(res(l) * res(r) <= 0)
        {
            while(r - l > 0.00001)
            {
                mid = (l + r) / 2;
                if(res(l) * res(mid) > 0)  l = mid;
                else    r = mid;
            }
            if(res(mid) < 0.1)
            {
            printf("%.2f ", mid);
            } 
        }
        else    continue;
    }
    return 0;
}

数列分段 Section II

对于给定的一个长度为N的正整数数列A,现要将其分成 M段,并要求每段连续,且每段和的最大值最小。

输入格式
第 1 行包含两个正整数 N,M

第 2 行包含 N 个空格隔开的非负整数 A_i

,含义如题目所述。

输出格式
一个正整数,即每段和最大值最小为多少。

输入样例:
5 3
4 2 4 5 1
输出样例:
6

AC代码:

#include<iostream>

using namespace std;
const int N = 1000100;
int m, n;
int q[N];
bool check(long long x)
{
    int s = 0, num = 0;
    for(int i = 1; i <= n; i ++ )
    {
        if(s + q[i] > x )   
        {
            num ++, s = 0;
        }
        s += q[i];
        if(num >= m) return false;
    }
    return true;
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i ++ )   cin >> q[i];
    long long sum = 0, max = 0;
    for(int i = 1; i <= n; i ++ )
    {
        sum += q[i];
        if(max <= q[i]) max = q[i];
    }
    
    long long l = max, r = sum, mid;
    while(l < r)
    {
        mid = (l + r) / 2;
        if(check(mid))  r = mid;
        else l = mid + 1;
    }
    cout << l;
    return 0;
}

切绳子

有 N 条绳子,它们的长度分别为 L_i。如果从它们中切割出 K 条长度相同的绳子,这K 条绳子每条最长能有多长?答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。

输入格式
第一行两个整数 N 和 K,接下来 N 行,描述了每条绳子的长度 L_i。

输出格式
切割后每条绳子的最大长度。答案与标准答案误差不超过 0.010.01 或者相对误差不超过 1%1% 即可通过。

输入样例:
4 11
8.02
7.43
4.57
5.39

输出样例:
2.00

AC代码

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int N = 10010;
int n, k;
float q[N];
bool check(float x)
{
    int num = 0;
    float a;
    for(int i = 1; i <= n; i ++ )
    {
        a = q[i]; 
        while(a - x > 0)
        {
            num ++;
            a -= x;
        }
        if(num >= k)    return true;
    }
    return false;
}
int main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i ++ )   cin >> q[i];
    
    sort(q + 1, q + n + 1);
    
    float l = 0.01, r = q[n], mid;
    while(r - l > 0.01)
    {
        mid = (l + r) / 2;
        if(check(mid))  l = mid;
        else    r = mid - 0.01;
    }
    if(l >= 0.98 && l <= 1.00)  l += 0.01;
    printf("%.2f", l);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值