首页 > 其他分享 >二分

二分

时间:2023-02-19 23:45:14浏览次数:29  
标签:二分 int double 样例 mid while

目录

二分本质
给定一个具有单调性的区间 \([l,r]\),中间切一刀 \(mid=(l+r)/2;\) 可以将区间分为两个子区间,其合法的答案一定在其中的一个子区间中,继续对该区间进行二分。

按照上述原理,有一个问题:\(mid\) 这个位置分给左右那个区间?
(1)分给左区间,相当于:\([l,r] = [l,mid] + [mid+1,r]\); // 找右边界
(2)分给右区间,相当于:\([l,r] = [l,mid-1] + [mid,r]\); // 找左边界

【整数二分】起止位置

有 n 位同学按照年龄从小到大排好队。
王老师想要进行 q 次查询,年龄为 x 的同学,在队伍中首次出现的位置和最后一次出现的位置;如果队伍中不存在年龄为 x 的同学,请输出 -1。

输入格式:
第一行包含整数 n 和 q,表示队伍中的总人数和询问个数。
第二行包含 n 个整数(均在1~10000范围内),表示队伍中每个人的年龄。
接下来 q 行,每行包含一个整数x,表示一次询问的值。

输出格式:
共 q 行,每行包含两个整数,表示所求年龄在队伍中的起始位置和终止位置。
如果数组中不存在该元素,则返回"-1 -1"。

数据范围: 1≤n≤100000, 1≤q, x≤10000。

输入样例 输出样例
6 3
1 2 2 2 3 3
2
1
8
2 4
1 1
-1 -1

分析: 单次询问要做到 \(log_2n\) 级别,考虑二分查找左右边界。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,x,a[N];
// 求 x 出现的右边界, [l,r] = [l,mid] + [mid+1,r]
int lower(int l,int r, int x) { 
    while(l<r) {
        int mid=l+r>>1;
        if(a[mid]>=x) r=mid;
        else l=mid+1;
    }
    if(a[l]!=x) l=-1; return l;
}
// 求 x 出现的左边界, [l,r] = [l,mid-1] + [mid,r]
int upper(int l,int r,int x) {
    while(l<r) {
        int mid=l+r+1 >>1;
        if(a[mid]<=x) l=mid;
        else r=mid-1;
    }
    if(a[l]!=x) l=-1; return l;
}
int main() {
    cin>>n>>m;
    for(int i=1; i<=n; i++) cin>>a[i];
    while(m--) {
        cin>>x;
        cout<<lower(1,n,x)<<" "<<upper(1,n,x)<<endl;
    }
    return 0;
}

【小数二分】求算术平方根

给定 n,求 \(\sqrt{n}\),保留小数点后 6 位。

输入样例 输出样例
3.14
1.772005
  • 牛顿迭代

\[令 a×b=n,a=n, 则 b=n/a; \\ 取 a_1 = (a+b)/2, b_1=n/a_1;\\ 取 a_2 = (a_1+b_1)/2, b_2=n/a_2;\\ ..., 直到 |a_i-b_i|<eps,\\ 那么认为 a_i=b_i,即 a_i×b_i={a_i}^2=n; \\ a_i =\sqrt{n}\]

  • 小数二分
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
double sqr1(double n) { // 牛顿迭代
    double a=n;
    while(abs(a-n/a) > eps) {
        a = (a+n/a) / 2;
    }
    return a;
}
double sqr2(double n) { // 小数二分
    double l=0, r=n;
//    while(r-l > eps){  // 写法 1
    for(int i=1; i<=100; i++) { // 写法 2:直接枚举100次
        double mid = (l+r)/2;
        if(mid*mid >= n) r=mid;
        else l=mid;
    }
    return l;
}
int main() {
    double n=3.14;
    printf("%.6lf\n", sqrt(n));
    printf("%.6lf\n", sqr1(n));
    printf("%.6lf\n", sqr2(n));
}

【二分答案】切割绳子

有 n 条绳子,每条绳子的长度已知且均为正整数。绳子可以以任意正整数长度切割,但不可以连接。现在要从这些绳子中切割出 m 条长度相同的绳段,求绳段的最大长度是多少。

输入格式:
第一行是一个不超过 100 的正整数 n。
第二行是 n 个不超过 \(10^6\) 的正整数,表示每条绳子的长度。
第三行是一个不超过 \(10^8\) 的正整数 m。

输出格式:
绳段的最大长度,若无法切割,输出“Failed”。

输入样例 输出样例
3
5 10 8
2
8

参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
int n,m,a[N];
// 检查 绳段的最大长度在 >= x 的情况下能否切割出至少 m 条绳子。
bool chk(int x){
    int s=0;
    for(int i=1; i<=n; i++) s += a[i]/x;
    return s >= m;
}
int main() {
    cin>>n;
    for(int i=1; i<=n; i++) cin>>a[i];
    cin>>m;
    int l=1, r=1e6;
    while(l < r){
        int mid = l+r+1 >> 1;
        if(chk(mid)) l=mid;
        else r=mid-1;
    }
    if(chk(l)) cout<<l;
    else cout<<"Failed";
    return 0;
}

标签:二分,int,double,样例,mid,while
From: https://www.cnblogs.com/hellohebin/p/17135960.html

相关文章

  • Educational Codeforces Round 143 (Rated for Div. 2) C(二分+差分维护)
    EducationalCodeforcesRound143(RatedforDiv.2)C(二分+差分维护)C.TeaTasting题目大意:给定n杯茶,n个人,一个进行n论赏茶,赏茶的规律如下:第1轮,第一个人喝第1杯茶,......
  • 二叉树||二叉树的遍历||排序二叉树||二分查找
    二叉树根节点叶子节点:左叶子节点右叶子节点树的层级树的高度二叉树的遍历广度优先遍历一层一层对节点进行遍历深度优先遍历前序:根......
  • ybtoj 第三章 二分
    T1:二分和的最大值从max~sum每次check最小可以分成的份数若<=m则合法r=mid否则不合法l=mid+1intnow=0;intcnt=1;now=a[1];这样就ojbk了T2:直接二分从1......
  • 经典算法之二分法
    二分法原理我们假设一下,你的女朋友买了件衣服,告诉你衣服的价格在200~2000之间,让你猜这件衣服的价格,怎么猜才能猜的最快呢?正确答案是:不猜,直接给女朋友转2000(手动狗头)。......
  • 二分查找
       二分查找又叫折半查找,指的是每次查找的范围减半,与枚举算法相比,二分查找具有比较次数少,查找速度快,平均性能好等优点,缺点是要求待查找的数据已被整理为有......
  • 二分查找水题--疯牛(POJ 2456)
    DescriptionFarmerJohnhasbuiltanewlongbarn,withN(2<=N<=100,000)stalls.Thestallsarelocatedalongastraightlineatpositionsx1,...,xN(0<=x......
  • 牛客小白月赛12 -- E 华华给月月准备礼物 (二分)
     题目描述二月中旬虐狗节前夕,华华决定给月月准备一份礼物。为了搭建礼物的底座,华华需要若干根同样长的木棍。华华手头上有一些长度参差不齐的木棍,他想将每根都裁剪成若干......
  • 二分模板
    例题:AcWing789.数的范围原题:使用二分查找数值\(x\)的范围\([l,r)\)。注意:采用左闭右开的方式,这个时候返回右端点时会比最大编号多一,输出时要\(-1\)。而求最小编......
  • D. Moving Dots(组合数学,贡献,二分/双指针)
    题目https://codeforces.com/contest/1788/problem/D思路从题目给的“2”这个信息入手,从贡献这个方面来考虑对于任意两不同的点,具有一定的范围,让这个范围内的点都被......
  • 2.二分查找新方法
    2.二分查找目录2.二分查找2.1新方法2.2例子162.寻找峰值2.1新方法近日重写二分查找的算法题还是倍感疑惑,在边界问题上还是有问题。在B站学习的时候,学到了一种新的理......