首先定义check(mid)的规则是 x 右边的数是 >= x,如果q[mid] >= x,表示答案x在左半边。
然后定义check(mid)的规则是 x 左边的数是 <= x,如果q[mid] <= x,表示答案x在右半边,x左边的数均满足 <= x。
#includeusingnamespace std;constint N =1e6+10;int n, m;int q[N];intmain(){scanf("%d%d",&n,&m);// n表示多少个数字,m表示要查询的个数for(int i =0;i < n; i++)scanf("%d",&q[i]);while(m--)// 有三个数需要查询{// 本题中 前一个3是用模板1求起始位置,后一个3是用模板2求终止位置int x;scanf("%d",&x);// 从前往后找int l =0, r = n -1;while(l < r){int mid = l + r >>1;// (l + r)/2if(q[mid]>= x) r = mid;else l = mid +1;}if(q[l]!=x) cout <<"-1 -1"<< endl;// 这里输出q[l] = q[r]else{
cout << l <<" ";// 从后往前找int l =0, r = n -1;while(l < r){int mid = l + r +1>>1;if(q[mid]<= x) l = mid;else r = mid -1;}
cout << l << endl;}}return0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2.2 浮点数二分
右边界不能小于1
2.2.1 模板
boolcheck(double x){/* ... */}// 检查x是否满足某种性质doublebsearch_3(double l,double r){constdouble eps =1e-6;// eps 表示精度,取决于题目对精度的要求while(r - l > eps){double mid =(l + r)/2;if(check(mid)) r = mid;else l = mid;}return l;// 也可以输出 r}
1
2
3
4
5
6
7
8
9
10
11
12
13
2.2.2 习题1(开根号)
不用考虑边界问题
#includeusingnamespace std;intmain(){double x;
cin >> x;double l =0, r = x;while(r - l >1e-8)// 如果结果保留6为小数,则写为e-8,多写两位{double mid =(l + r)/2;if(mid * mid >= x) r = mid;else l = mid;}printf("%lf",l);// 输出 l和r均可以return0;}
#includeusingnamespace std;intmain(){double x;
cin >> x;double l =-10000, r =10000;while(r - l >1e-8){double mid =(l + r)/2;if(mid * mid * mid >= x) r = mid;else l = mid;}printf("%lf",l);// 输出 l和r均可以return0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3 高精度
3.1 高精度加法
3.1.1 模板
// C = A + B, A >= 0, B >= 0
vector<int>add(vector<int>&A, vector<int>&B){if(A.size()< B.size())returnadd(B, A);
vector<int> C;int t =0;for(int i =0; i < A.size(); i ++){
t += A[i];if(i < B.size()) t += B[i];
C.push_back(t %10);
t /=10;}if(t) C.push_back(t);return C;}
#include#include#includeusingnamespace std;// C = A + B
vector<int>add(vector<int>&A, vector<int>&B){
vector<int> C;int t =0;for(int i =0;i < A.size()|| i < B.size(); i++){if(i < A.size()) t += A[i];if(i < B.size()) t += B[i];// t存储Ai + Bi + 上一位的进位
C.push_back(t%10);// 求余
t /=10;// 看是否有下一位的进位}if(t) C.push_back(1);// 最高位有没有进位return C;// 返回的是C的数组}intmain(){
string a, b;
vector<int>A, B;
cin >> a >> b;// a = "123456", 字符串a可以当作字符数组来处理, 处理后// 将a[]中阿拉伯数字字符转换成int数字,需要减去'0'', A 结果是 [6, 5, 4, 3, 2, 1],最低位是个位数,这种操作叫字符串转整型for(int i = a.size()-1; i >=0; i--) A.push_back(a[i]-'0');for(int i = b.size()-1; i >=0; i--) B.push_back(b[i]-'0');auto c =add(A,B);// auto 是自动推断变量的类型,auto 这里等价于 vector// 逆向输出,先输出最高位,因为之前的相加的结果的开头是最低位for(int i = c.size()-1;i >=0;i --)printf("%d",c[i]);// i从size - 1开始return0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
3.2 高精度减法
假如给出A < B,则先计算B - A,再在前面加"-"。
t 值的求法
3.2.1 模板
// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int>sub(vector<int>&A, vector<int>&B){
vector<int> C;for(int i =0, t =0; i < A.size(); i ++){
t = A[i]- t;if(i < B.size()) t -= B[i];// 先判断B的位数是否存在
C.push_back((t +10)%10);// 当t>=0时,直接赋值为t,当t<0时,t = t + 10,直接用(t+10)%10来表示这两种情况if(t <0) t =1;// t < 0,进一位,否则不进位else t =0;}while(C.size()>1&& C.back()==0) C.pop_back();return C;}
#include#include#includeusingnamespace std;// 判断是否有A >= B,假定A和B都是正数boolcmp(vector<int>&A, vector<int>&B){if(A.size()!= B.size())return A.size()> B.size();// 判断两者的位数,A的位数是否大于Bfor(int i = A.size()-1; i >=0; i--)// 从最高位开始比较,最高位在数组的最后的一位if(A[i]!= B[i])return A[i]> B[i];// 返回同一位较大的值returntrue;}// C = A - B
vector<int>sub(vector<int>&A, vector<int>&B){
vector<int> C;int t =0;for(int i =0;i < A.size(); i++){
t = A[i]- t;if(i < B.size()) t -= B[i];// 先判断B的位数是否存在
C.push_back((t +10)%10);// 当t >= 0时,直接赋值为t,当t<0时,t = t + 10,直接用(t+10)%10来表示这两种情况if(t <0) t =1;// t < 0,向前借一位,否则不借位else t =0;}while(C.size()>1&& C.back()==0) C.pop_back();// C.back表示最后一位等于零的话,就弹出来,就是要丢掉前导零,比如123 - 120 = 003,输出的结果C是300,去掉最后的两个零,变成3return C;}intmain(){
string a, b;
vector<int>A, B;
cin >> a >> b;// a = "123456", 字符串a可以当作字符数组来处理, 处理后// 将a[]中阿拉伯数字字符转换成int数字,需要减去'0'', A 结果是 [6, 5, 4, 3, 2, 1],最低位是个位数,这种操作叫字符串转整型for(int i = a.size()-1; i >=0; i--) A.push_back(a[i]-'0');for(int i = b.size()-1; i >=0; i--) B.push_back(b[i]-'0');if(cmp(A,B))// 判断A与B大小关系,在A >= B的情况下,再进行A - B的操作{auto c =sub(A,B);// auto 是自动推断变量的类型,auto 这里等价于 vector// 逆向输出,先输出最高位,因为之前的相加的结果的开头是最低位for(int i = c.size()-1;i >=0;i --)printf("%d",c[i]);// i 从size - 1开始}else{auto c =sub(B,A);printf("-");// 当 A < B时,先求B - A,再在前面添加"-"for(int i = c.size()-1;i >=0;i --)printf("%d",c[i]);// i从size - 1开始}return0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
3.3 高精度乘以低精度
3.3.1 模板
// C = A * b, A >= 0, b >= 0
vector<int>mul(vector<int>&A,int b){
vector<int> C;int t =0;for(int i =0; i < A.size()|| t; i ++){if(i < A.size()) t += A[i]* b;
C.push_back(t %10);
t /=10;}while(C.size()>1&& C.back()==0) C.pop_back();return C;}
#include#includeusingnamespace std;
vector<int>mul(vector<int>&A,int b){
vector<int> C;int t =0;for(int i =0;i < A.size()|| t;i ++)// i没有循环完或者t不为零{if(i < A.size())t += A[i]* b;// t = A[i] * b + t
C.push_back(t %10);
t /=10;// t = t / 10}while(C.size()>1&& C.back()==0) C.pop_back();// C.back表示最后一位等于零的话,就弹出来,就是去掉前导零return C;}intmain(){
string a;// 长数字用字符串处理,一般小数字用int保存int b;
cin >> a >> b;
vector<int>A;for(int i = a.size()-1;i >=0;i --) A.push_back(a[i]-'0');auto C =mul(A,b);// 这里是A,就是处理后的vector数组for(int i = C.size()-1;i >=0;i --)printf("%d", C[i]);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
3.4 高精度除以低精度
3.4.1 模板
// A / b = C ... r, A >= 0, b > 0
vector<int>div(vector<int>&A,int b,int&r){
vector<int> C;
r =0;for(int i = A.size()-1; i >=0; i --){
r = r *10+ A[i];
C.push_back(r / b);
r %= b;}reverse(C.begin(), C.end());while(C.size()>1&& C.back()==0) C.pop_back();return C;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3.4.2 习题
#include#include#includeusingnamespace std;// C = A / B, 商是C,余数是r。除法是从最高位开始计算
vector<int>div(vector<int>&A,int b,int&r)// r位引用{
vector<int>C;
r =0;// 刚开始余数位0for(int i = A.size()-1;i >=0;i --){
r = r *10+ A[i];// 余数
C.push_back(r/b);// 求商
r %= b;}reverse(C.begin(),C.end());while(C.size()>1&& C.back()==0) C.pop_back();// 数组最后一位是零的话,会自动弹出来,清除前导零return C;}intmain(){
string a;// 长数字用字符串处理,一般小数字用int保存int b;
cin >> a >> b;
vector<int>A;for(int i = a.size()-1;i >=0;i --) A.push_back(a[i]-'0');int r =0;auto C =div(A,b,r);// 这里是A,就是处理后的vector数组for(int i = C.size()-1;i >=0;i --)printf("%d", C[i]);// 输出商
cout << endl;
cout << r << endl;// 输出余数}