二分法

1. 二分查找法代码实现:

 1 // 二分查找法
 2 // A[]为严格递增序列,left为二分下界,x为欲查询的数
 3 // 二分区间为左闭右闭的[left, right], 传入的初值为[0, n-1]
 4 int binarySearch(int A[], int left, int right, int x){
 5     int mid;
 6     while (left <= right){
 7         mid = (left + right) / 2;  // mid = left + (right - left) / 2;
 8         if (A[mid] == x){
 9             return mid;
10         }
11         else if (A[mid] > x){
12             right = mid - 1;
13         }
14         else if (A[mid] < x){
15             left = mid + 1;
16         }
17     }
18 
19     return -1;
20 }

 

2. 二分法求序列中第一个大于等于x的元素的位置L

 1 // 求序列中第一个大于等于x的元素的位置L
 2 // 二分上下界为左闭右闭的[left, right], 传入的初值为[0, n]
 3 int lower_bound(int A[], int left, int right, int x){
 4     int mid;
 5     while (left < right){
 6         mid = (left + right) / 2;        
 7         if (A[mid] >= x){
 8             right = mid;
 9         }
10         else{
11             left = mid + 1;
12         }
13     }
14     return left;            // 返回夹出来的位置
15 }

 

3. 二分法求序列中第一个大于x 的元素的位置R

 1 int upper_bound(int A[], int left, int right, int x){
 2     int mid;
 3     while (left < right){
 4         mid = (left + right) / 2;
 5         if (A[mid] > x){
 6             right = mid;
 7         }
 8         else{
 9             left = mid + 1;
10         }
11     }
12     return left;
13 }

 

4. 二分法解决“寻找有序序列第一个满足某条件的元素的位置”问题的固定模板

 1 // 二分区间为左闭右闭[left, right], 初值必须能覆盖解的所有取值
 2 int solve(int left, int right){
 3     int mid;
 4     while (left < right){
 5         mid = (left + right) / 2;
 6         if (条件成立){
 7             right = mid;
 8         }
 9         else{
10             left = mid + 1;
11         }
12     }
13 
14     return left;
15 }

 

5. 二分法求根号2的近似值

 1 double calSqrt(){
 2     double left = 1, right = 2, mid;        // [left, right] = [1, 2]
 3     while (right - left > eps){
 4         mid = (left + right) /2;
 5         if (f(mid) > 2){
 6             right = mid;
 7         }
 8         else{
 9             left = mid;
10         }
11     }
12 
13     return mid;
14 }

 

6. 二分法求某个单调函数根的近似值

 1 // 利用二分法求单调函数的根
 2 const double eps2 = 1e-5;
 3 double f(double x){
 4     return ...;            // 写函数的表达式
 5 }
 6 
 7 double solve(double L, double R){
 8     double left = L, right = R, mid;
 9     while (right - left > eps2){
10         mid = (left + right) / 2;
11         if (f(mid) > 0){
12             right = mid;
13         }
14         else{
15             left = mid;
16         }
17     }
18     return mid;
19 }            

 

7. 快速幂的递归写法(二分法实现)

 1 // 快速幂的递归写法
 2 typedef long long LL;
 3 // a^b & m
 4 LL binaryPow(LL a, LL b, LL m){
 5     if (b == 0)
 6         return 1;
 7     if (b & 1){            // 如果b为奇数
 8         return a * binaryPow(a, b - 1, m) % m;
 9     }
10     else{
11         LL mu = binaryPow(a, b / 2, m);
12         return mu * mu % m;
13     }
14 }

 

 

二分使用实战:

        1030 完美数列 (25分)

给定一个正整数数列,和正整数 p,设这个数列中的最大值是 M,最小值是 m,如果 Mmp,则称这个数列是完美数列。

现在给定参数 p 和一些正整数,请你从中选择尽可能多的数构成一个完美数列。

输入格式:

输入第一行给出两个正整数 N 和 p,其中 N(105​​)是输入的正整数的个数,p(109​​)是给定的参数。第二行给出 N 个正整数,每个数不超过 109​​。

输出格式:

在一行中输出最多可以选择多少个数可以用它们组成一个完美数列。

输入样例:

10 8
2 3 20 4 5 1 6 7 8 9
 

输出样例:

8

 

分析:输入数据到数组,对数组进行排序,对每个元素用二分法求出第一个大于 a[i] * p 的元素的位置 j ,(j - i) 即为完美数列的长度,将所有长度取最大值即为结果

代码:这里用到了上面求序列中第一个大于x 的元素的位置R的函数upper_bound()

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 long long a[100010] = { 0 };
 8 
 9 long long upper_bound(long long A[], long long left, long long right, long long x){
10     long long mid;
11     while (left < right){
12         mid = (left + right) / 2;
13         if (A[mid] > x){
14             right = mid;
15         }
16         else{
17             left = mid + 1;
18         }
19     }
20     return left;
21 }
22 
23 int main()
24 {
25     freopen("in.txt", "r", stdin);
26     long long ans = 1;        //  存储“完美数列”的最大长度
27     long long n, p;
28     scanf("%lld %lld", &n, &p);
29 
30     // 读取输入
31     for (long i = 0; i < n; i++){
32         scanf("%lld", &a[i]);
33     }
34     // 排序
35     sort(a, a + n);
36     // 遍历数组,对每个元素都查找最大值的位置j,区间长度与ans比较,取较大者
37     for (long long i = 0; i < n; i++){
38         // 寻找第一个大于a[i] * p的元素的位置
39         long long j = upper_bound(a, i + 1, n, a[i] * p);
40         ans = max(ans, j - i);
41     }
42     printf("%lld\n", ans);
43     fclose(stdin);
44     return 0;
45 }
posted @ 2020-01-19 18:19  Lucky小黄人^_^  阅读(338)  评论(0编辑  收藏  举报