Module1-Two templates of integer dichotomy + floating-point dichotomy template and application

Insert picture description here
The dividing point can be found with the idea of ​​dichotomy.
Suppose we want to divide the red (the range that does not satisfy the condition) in two:

  1. Find an intermediate value mid: l+r >> 1
  2. Write a function check() to determine whether mid is within the range of satisfying conditions (green) or not satisfying (red).
  3. (Note: Why is l+r+1 here)
    For example:
    If l = r-1 (that is, the left and right boundaries differ by only 1), suppose it is l+r >> 1 (rounded down) suppose if(check(mid )) is judged to be true (at this time mid = l + r >> 1 == l), then execute l=mid; l=mid=l; in an infinite loop, the left and right boundaries are always [l, r] unchanged.
    If it is l +r+1>>1 This problem will not occur (for details, please refer to the derivation above).
    Insert picture description here

Two integer dichotomies template

//模板1
/———————————————————————————————— 整数二分模板1 ————————————————————————————————\
bool check(int x) {
    
    /* ... */ } // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    
    
	while (l < r)
	{
    
    
		int mid = l + r >> 1;
		if (check(mid)) r = mid;    // check()判断mid是否满足性质
		else l = mid + 1;
	}
	return l;
}
\———————————————————————————————— 整数二分模板1 ————————————————————————————————/
//模板2
/———————————————————————————————— 整数二分模板2 ————————————————————————————————\
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    
    
	while (l < r)
	{
    
    
		int mid = l + r + 1 >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	return l;
}
\———————————————————————————————— 整数二分模板2 ————————————————————————————————/

Two integer dichotomy template application

Given a length in ascending order as nnan integer array of n , andqqq queries.

For each query, return the starting position and ending position of an element k (the position starts counting from 0).

If the element does not exist in the array, "-1 -1" is returned.

Input format The
first line contains the integer nnn andqqq indicates the length of the array and the number of queries.

The second line contains nnn integers (all in1 11 ~ 10000 10000 1 0 0 0 0 ), which means a complete array.

Next q lines, each line contains an integer kkk represents a query element.

Output format
total qqLine q , each line contains two integers, indicating the starting position and ending position of the requested element.

If the element does not exist in the array, "-1 -1" is returned.

Data range
1 ≤ n ≤ 100000 1≤n≤1000001n100000
1 ≤ q ≤ 10000 1≤q≤10000 1q10000
1 ≤ k ≤ 10000 1≤k≤10000 1k1 0 0 0 0
Input example:

6 3
1 2 2 3 3 4
3
4
5

Sample output:

3 4
5 5
-1 -1

Code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<algorithm>
 
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1e9 + 7
using namespace std;
int read()
{
    
    
	int w = 1, s = 0;
	char ch = getchar();
	while (ch < '0' || ch>'9') {
    
     if (ch == '-') w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') {
    
     s = s * 10 + ch - '0';ch = getchar(); }
	return s * w;
}
//最大公约数
int gcd(int x,int y) {
    
    
    if(x<y) swap(x,y);//很多人会遗忘,大数在前小数在后
    //递归终止条件千万不要漏了,辗转相除法
    return x % y ? gcd(y, x % y) : y;
}
//计算x和y的最小公倍数
int lcm(int x,int y) {
    
    
    return x * y / gcd(x, y);//使用公式
}
int ksm(int a, int b, int mod) {
    
     int s = 1; while(b) {
    
    if(b&1) s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
//------------------------ 以上是我常用模板与刷题几乎无关 ------------------------//
const int N = 100010;

int a[N];

signed main()
{
    
    
    int n = read(), m = read();
    for (int i = 0 ;i < n; i++) a[i] = read();
    while (m--) {
    
    
        int x = read();
        //模板1
        /-------------------\
        int l = 0, r = n - 1;
        while (l < r) {
    
    
            int mid = l + r >> 1;
            if (a[mid] >= x) r = mid;
            else l = mid + 1;
        }
        \-------------------/
        if (a[l] != x) printf("-1 -1\n");
        else {
    
    
        	//这里二分完,l和r是一样的,输出什么都可以
            printf("%lld ", l);
            //模板2
            /-------------------\
            int l = 0, r = n - 1;
            while (l < r) {
    
    
                int mid = l + r + 1 >> 1;
                if (a[mid] <= x) l = mid;
                else r = mid - 1;
            }
            \-------------------/
            //这里二分完,l和r是一样的,输出什么都可以
            printf("%lld\n", r);
        }
    }
    return 0;
}

Floating point dichotomous template

Floating point binary analysis

Insert picture description here

The dividing point can be found with the idea of ​​dichotomy.
Suppose we want to divide the red (the range that does not satisfy the condition) in two:

  1. Find an intermediate value mid: l+r >> 1 (because it is a floating point number, it can be strictly dichotomy, that is, mid is the midpoint)
  2. Write a function check() to determine whether mid is within the range of satisfying conditions (green) or not satisfying (red).
  3. When the interval length is very small, it can be approximated as finding the answer, for example: rl ≤ 10 − 6 ^{-6}6 (If the title requires 4 decimal places, it should be written to the power of -6, which is 2 more than the effective decimal place)

Example: Use dichotomy to make a sqrt function (only the root of ≥1 can be calculated)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<algorithm>
 
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define int ll
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MOD 1e9 + 7
using namespace std;
int read()
{
    
    
	int w = 1, s = 0;
	char ch = getchar();
	while (ch < '0' || ch>'9') {
    
     if (ch == '-') w = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') {
    
     s = s * 10 + ch - '0';ch = getchar(); }
	return s * w;
}
//最大公约数
int gcd(int x,int y) {
    
    
    if(x<y) swap(x,y);//很多人会遗忘,大数在前小数在后
    //递归终止条件千万不要漏了,辗转相除法
    return x % y ? gcd(y, x % y) : y;
}
//计算x和y的最小公倍数
int lcm(int x,int y) {
    
    
    return x * y / gcd(x, y);//使用公式
}
int ksm(int a, int b, int mod) {
    
     int s = 1; while(b) {
    
    if(b&1) s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
//------------------------ 以上是我常用模板与刷题几乎无关 ------------------------//

signed main()
{
    
    
	double x;
	scanf("%lf", &x);
	double l = 0 , r = x;
	//如果题目要求保留4位小数,则应该写到-6次方,比有效小数的位数多2
	while (r - l > 1e-6) {
    
    
	//还可以写成 for(int i = 0; i < 100; ++i) 循环100次相当于整个区间/ 2的100次方,最后的结果也是很精确的。
		double mid = (l + r) / 2;
		if (mid * mid >= x) r = mid;
		else l = mid;
	}

	printf("%lf\n",l);
	return 0;
}

Guess you like

Origin blog.csdn.net/m0_46272108/article/details/112740679