【算法基础】第一章:基础算法

Chapter 1 基础算法

1:快速排序

【1】确定分界点。x = q[l], q[r], q[(r+l)/2]都可以

【2】调整区间,使得左段<=x ,右段>x

【3】递归处理左右两段

暴力:

【1】开辟a[N], b[N]

【2】把小于等于x的数放在a[N],大于x的数放在b[N]

【3】遍历a[N], b[N],按大小顺序拷贝到q[N]

双指针:

# include <iostream>
using namespace std;

const int N = 1e6+10;

int n;
int q[N];

// basic quick sort
void quick_sort(int q[], int l, int r){
    if(l >= r) return;
    // judge the boundary
    
    int i=l-1,j=r+1;
    int x=q[r+l >> 1];
    // initiate x, i, j
    
    while(i < j){
        do i++; 
		while(q[i]<x);
		
        do j--; 
		while(q[j]>x);
		
        if(i < j) swap(q[i],q[j]);
    }
    
    // 如果x=q[l],则必须写成j和j+1
    quick_sort(q, l, j);
    quick_sort(q, j+1, r);
}


int main(){
    scanf("%d",&n);
    for(int i=0; i<n; i++){
        scanf("%d", &q[i]);
    }
    
    quick_sort(q, 0, n-1);
    
    for(int i=0; i<n; i++){
        printf("%d", q[i]);
    }
    
    return 0;
}
/*
5 3
2 4 1 5 3

3
*/

2:归并排序

分治法

【1】确定分界点mid = (l+r)/2

【2】递归排序left和right

【3】归并,然后合二为一

双指针:

#include <iostream>
using namespace std;

const int N=1e6+10;

int n;
int q[N], tmp[N];

void merge_sort(int q[], int l, int r){
    if(l >= r) return;
    
    int mid = l+r >> 1;
    
    // 递归左右两侧
    merge_sort(q, l, mid);
    merge_sort(q, mid+1, r);
    
    int k=0, i=l, j=mid+1; // i是左侧数组的起点,j是右侧数组的起点
    while(i <= mid && j <= r){ // i和j都在数组范围内
        if(q[i] <= q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    }
    while(i <= mid) tmp[k++] = q[i++]; // 左侧还有数
    while(j <= r) tmp[k++] = q[j++]; //右侧还有数
    
    // 拷贝tmp到q(额外空间tmp开销)
    for(i = l, j = 0; i <= r; i++, j++){
        // i从左侧数组起点l开始,j从tmp数组起点0开始
        q[i] = tmp[j];
    }
}

int main(){
    scanf("%d, &n");
    for(int i=0; i<n; i++){
        scanf("%d", &q[i]);
    }
    
    merge_sort(q, 0, n-1);
    
    for(int i=0; i<n; i++){
        printf("%d", q[i]);
    }
    
    return 0;
}

3:整数二分

—0—0—0—0—0—x(0)—y(1)—1—1—1—1—1—1—1—

1:右侧都满足check

0:左侧都不满足check

y为1的边界

x为0的边界

方法1(得到x

【1】确定分界点:mid = (l+r+1)/2

【2】检查mid是否符合条件(即取0),若true(取0了),则答案在[mid, r]内,更新l = mid;若false(取1了),则答案在[l, mid-1]内,更新r = mid-1

// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1; // 一定要加1,否则会出现边界问题!
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

方法2(得到y

【1】确定分界点:mid = (l+r)/2

【2】检查mid是否符合条件(即取1),若true(取1了),则答案在[l, mid]内,更新r = mid;若false(取0了),则答案在[mid+1, r]内,更新l = mid+1

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

题目:数的范围

给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。

如果数组中不存在该元素,则返回 -1 -1

输入格式:

第一行包含整数 n 和 q,表示数组长度和询问个数。

第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

#include <iostream>
using namespace std;

const int N=1e6+10;
int n,m;
int q[N];

int main(){
    scanf("%d%d", &n, &m);
    for (int i=0; i<n; i++) scanf("%d", &q[i]);
    
    while(m--){
        int x;
        scanf("%d", &x);
        int l = 0, r = n-1;
        
        // 起始位置判定
        while(l < r){
            int mid = l+r >> 1;
            if(q[mid] >= x) r = mid;  // 如果mid位置的数,不小于询问元素k
            else l = mid+1;
        }
        if(q[l] != x) cout<<"-1 -1"<<endl;
        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;
        }
    }
    return 0;
}

4:浮点二分

题目:大于1的数字的平方根

# include <iostream>
using namespace std;

int main(){
    double x;
    cin>>x;
    
    double l=0, r=x;
    while(r - l > 1e-8){
        double mid = (l+r)/2;
        
        if(mid * mid > x) r = mid;
        else l = mid;
    }
    printf("%lf\n", l);
    return 0;
}

5:高精度加法

【1】大整数存储(正整数),从个位开始(string to vector)

【2】Ai + Bi + 进位

#include <iostream>
#include <vector>
using namespace std;

const int N = 1e6+10;

// 加法
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];
        C.push_back(t%10);
        t /= 10;
    }
    if(t) C.push_back(1); //最高位有进位,例如9+2=11,1需要进位
    return C;
}

int main(){
	string a,b;
    vector<int> A, B;
    cin>>a>>b;
   	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);
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    return 0;
}

6:高精度减法

【1】大整数存储(正整数),从个位开始(string to vector)

【2】Ai - Bi + 结位

#include <iostream>
#include <vector>
using namespace std;

const int N = 1e6+10;

// 判断A>=B
bool cmp(vector<int> &A, vector<int> &B){
    // 判断bit-size
    if(A.size() != B.size()) return A.size() > B.size();
    for(int i=A.size()-1;i>=0;i--){
        if(A[i]!=B[i]) return A[i]>B[i];
    }
    return 1; // 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]; // 减数仍然存在
        C.push_back((t+10) % 10);	
        if(t < 0) t = 1;	// 有借位
        else t = 0;			// 没有借位
    }
    while (C.size()>1 && C.back()==0) C.pop_back() // 去除前导0,例如01
    return C;
}

int main(){
	string a,b;
    vector<int> A, B;
    cin>>a>>b;
   	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');
    
    // A >= B
    if(cmp(A, B)){
        auto C = sub(A, B);
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }
    else{
        auto C = sub(A, B);
        cout<<"-";
        for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    }
    return 0;
}

7:高精度乘法

【1】大整数存储(正整数),从个位开始(string to vector)

【2】b看成一个整体,和A相乘(A是大整数,B是小整数)

#include <iostream>
#include <vector>
using namespace std;

// multiply
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;
    }
    return C;
}

int main(){
    string a;
    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);
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    return 0;
}

8:高精度除法

【1】大整数存储(正整数),从个位开始(string to vector)

【2】b看成一个整体,和A相除(A是大整数,B是小整数),从最高位开始算(一般会有前导0)

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// divide
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());
    // 因为除法是从高位开始,因此需要reverse
    while(C.size()>1 && C.back()==0) C.pop_back();
	// 去除前导0    
    return C;
}

int main(){
    string a;
    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; //余数
    auto C = div(A, b, r);
    for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
    cout<<endl<<r<<endl;
    return 0;
}

9:前缀和

作用:一次运算求出某一段区间的所有数据的和

【1】数组定义:原数组为A[],前缀和为S[]

【2】前缀和Si = a1 + a2 + ... + ai,其中S0 = 0

题目:一维前缀和

求出区间[l, r]之间数的和

#include <iostream>
using namespace std;

const int N = 1e6+10;

int n, m;
int a[N], S[N];

int main(){
    scanf("%d%d", &n, &m);
    a[0]=0;
    s[0]=0;
    for(int i=1;i<=n;i++) scanf("%d", &a[i]);
    
    for(int i=1;i<=n;i++) s[i] = s[i-1] + a[i];
    
    // m次询问
    while(m--){
        int l, r;
        scanf("%d%d", &l, &r);
        print("%d\n", s[r] - s[l-1]);
    }
    return 0;
}

题目:二维前缀和

求出某个子矩阵内数的和,左上角坐标为(x1, y1),右下角坐标为(x2, y2)

=>容斥定理

#include <iostream>
using namespace std;

const int N=1010;
int a[N][N], s[N][N];

int main(){
    int n,m,q;
    scanf("%d%d%d", &n, &m, &q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    
    // 2-dimensional matrix, n for rows, m for cols
    
    // 初始化前缀和
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
    
    // 计算子矩阵的部分和
    while(q--){
        int x1, x2, y1, y2;	// 1是左上角,2是右下角
        cin>>x1>>y1>>x2>>y2;
        printf("%d\n",s[x2][y2] - s[x1-1][y2] - s[x2][y1 -1] + s[x1-1][y1-1]);
    }
    return 0;
}

10:差分

本质:前缀和的逆运算

【1】构造b[],使得ai = b1 + b2 + ... + bi,即a是b的前缀和,b是a的差分

【2】一维计算公式:b[n] = a[n] - a[n-1]

【2】二维计算公式:b[i][j] = a[i][j] − a[i−1][j] − a[i][j−1] + a[i−1][j−1],容斥定理

【3】初始化:可以假定全数组都是0,然后在[i,i]区间加上a[i]

用途:

【1】一维:在某个区间[l,r]的多次操作都加上或减去一个数x

【2】二维:在一个二维矩阵中,有多块区间需要增加或减少一个数值,多次操作后求最终的矩阵内容

题目:一维差分

#include <iostream>
using namespace std;

const int N = 1e6+10;

int n,m;
int a[N],b[N];

void insert(int l, int r, int c){
    b[l] += c;
    b[r+1] -= c;
}

int main(){
    scanf("%d%d",&n, &m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]); //数据读入
    for(int i=1;i<=n;i++) insert(i,i,a[i]);	//差分初始化
    //a[0]=0 
    //b[0]=0
    
    // 执行m次,对每一次输入的区间[l,r]的数加上c
    while(m--){
        int l,r,c;
        cin>>l>>r>>c;
        insert(l,r,c);
    }
    
    for(int i=1;i<=n;i++) b[i] += b[i-1]; // 还原a[i]
    for(int i=1;i<=n;i++) cout<<b[i]<<" ";
    return 0;
}

题目:二维差分

#include <iostream>
using namespace std;

const int N = 1010;
int n,m,q;
int a[N][N],b[N][N]; // a是原数组,b是差分数组

void insert(int x1, int y1, int x2, int y2, int c){
    b[x1][y1] += c;
    b[x2+1][y1] -= c;
    b[x1][y2+1] -= c;
    b[x2+1][y2+1] += c;
}

int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    
    // 差分二维矩阵初始化,在空集子矩阵上插入a[i][j]
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            insert(i,j,i,j,a[i][j]);
    
    while(q--){
        int x1,x2,y1,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;	//c是子矩阵需要加减的数
        insert(x1,y1,x2,y2,c); // 在差分数组上,需要加减的子矩阵上插入数c
    }
    
    // 从差分矩阵还原到原矩阵
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            //b[i][j] += b[i-1][j]+b[i][j-1]-b[i-1][j-1]; 
            a[i][j] = a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1] + b[i][j]; // 从b还原到a
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++) printf("%d ",a[i][j]); // 输出
        puts("");
    }
    return 0;
}
/*
input test
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
*/

/*
output test
2 3 4 1
4 3 4 1
2 2 2 2
*/

11:双指针

核心:将O(n^2)优化到O(n)

朴素算法:

for(int i=0;i<n;i++)
	for(int j=0;j<n;j++)
		function();

双指针算法:

for(int i=0,j=0;i<n;i++){
    while(j<i && check(i,j)){
        j++;
    }
    function();
}

题目:分割一句英文的每个单词,每个单词按空格隔开

#include <string.h>
#include <iostream>
using namespace std;

int main(){
    char a[1000];
    gets(a);
    int n=strlen(a);
    for(int i=0;i<n;i++){
        int j=i;
        while(j<n && a[j]!=' '){
            j++;
        }
        for(int k=i;k<j;k++) cout<<a[k];
        cout<<endl;
        
        i=j;
    }
    return 0;
}

题目:最长连续不重复子序列

给定一个长度为n的整数序列,找出最长的不包含重复数字的连续子序列,输出其长度

#include <string.h>
#include <iostream>
using namespace std;

const int N=1e6+10;
int a[N],s[N];

int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    
    int res=0;
    for(int i=0, j=0;i<n;i++){
        s[a[i]]++;	// hash中,对应的数值计数+1
        while(s[a[i]]>1){ // 检测到有重复的值
            s[a[j]]--;
            j++;
        }
        res=max(res,i-j+1);
    }
    cout<<res<<endl;
    return 0;
}
/*
5
1 2 2 3 5

3
*/

12:位运算

作用:n的二进制表示中,第k位是几

【1】先把第k位移到最后一位,采用n>>k

【2】看个位是几,采用x&1

#include <string.h>
#include <iostream>
using namespace std;

int main(){
    int n=10;
    for(int k=3;k>=0;k--){
        cout<<(n>>k&1);
    }
    return 0;
}
//n的二进制表示

low bit运算:返回x的最后一位1

本质:x & -x = x & (~x + 1)

如果x = 10000010,则lowbit(x) = 10

题目:求每个十进制数,转化为二进制后1的个数

#include <string.h>
#include <iostream>
using namespace std;

int lowbit(int x){
    return x & -x;
}

int main(){
    int n;
    cin>>n;
    while(n--){
        int x;
        cin>>x;
        int res=0;
        while(x) x -= lowbit(x),res++;
        cout<<res<<endl;
    }
    return 0;
}

13:离散化

将稀疏的数据变为连续的整数值

例如下表,第一行是稀疏数据,第二行为离散化数据

本质:映射

a[0]a[1]a[2]a[3]a[4]
13100200050000
01234

题目:区间和

有一个无限长数轴,每个坐标上的数都是0

进行n次操作,每次在位置x上的数加c

进行m次循环,求出区间[l, r]内的所有数的和

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

typedef pair<int,int> PII;
const int N=3e6+10;
int n,m;
int a[N],s[N];

vector<int> alls;
vector<PII> add,query;

// integer binary search 
int find(int x){
	int l=0,r=alls.size()-1;
	while(l<r){
		int mid = l+r >> 1;
		if(alls[mid] >= x) r=mid;
		else l=mid+1;
	}
	return r+1;
}

int main(){
	cin>>n>>m; 
	
	for(int i=0;i<n;i++){
		int x,c;
		cin>>x>>c;
		add.push_back({x,c}); // append a key value
		alls.push_back(x);	// append location
	}
	
	for(int i=0;i<m;i++){
		int l,r;
		cin>>l>>r;
		query.push_back({l,r});
		alls.push_back(l);
		alls.push_back(r);
	}
	
	//去重,在位置数组alls中 
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(),alls.end()),alls.end());
	
	//处理插入
	for(auto item:add){
		int x = find(item.first); // 在alls中找到位置 
		a[x] += item.second;	// 加载数值,并求和 
	}
	
	// 预处理前缀和
	for(int i=1;i<=alls.size();i++){
		s[i]=s[i-1]+a[i];
	} 
	
	// 处理询问
	for(auto item:query){
		int l=find(item.first), r=find(item.second);
		cout<<s[r]-s[l-1]<<endl;
	} 
	return 0;
}
/*
3 3
1 2
3 6
7 5
1 3
4 6
7 8


8
0
5
*/

对于已经排序号的数组,unique的实现如下:

【1】当前是第一个数,即i == 0

【2】a[i] != a[i-1]

14:区间和并

作用:合并有交集的区间

【1】按区间左端点排序

【2】扫描每个区间,并维护当前区间;每个区间和当前区间有3种关系,①完全包含②部分交集③完全无交集

①当前维护区间[start, end]不变,类似[1,5]and[2,3]

②当前维护区间[start, end]更新为[start, new-end],类似[1,5]and[2,7]

③当前区间存放,将当前维护区间更新为[new-start, new-end],类似[1,5]and[7,8]

#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

typedef pair<int,int> PII;
const int N=1e6+10;
int n;
vector<PII> segs;

// 区间合并 
void merge(vector<PII> &segs){
	vector<PII> res;	// 临时变量 
	sort(segs.begin(),segs.end()); // 按照左端点排序 
	
	int bound=-2e9; // 负无穷边界值 
	int start=bound,end=bound; // 维护区间的初始化为[负无穷, 负无穷]
	
	for(auto seg:segs){	// 遍历每一个区间 
		// 如果下一个区间完全不相交 
		if(end < seg.first){	
			if(start != bound) res.push_back({start,end}); // 如果不是一开始的初始区间 
			
			// 更新维护区间
			start = seg.first;  
			end = seg.second; 
		}
		// 有相交 
		else end = max(end,seg.second);	// 维护右侧 
	}
	if (start != bound) res.push_back({start,end});
	segs=res;
}

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		int l,r;
		cin>>l>>r;
		segs.push_back({l,r});
	}
	merge(segs);
	cout<<segs.size()<<endl;
	return 0;
}
/*
5
1 2
2 4
5 6
7 8
7 9


3
*/

习题!

1:第k个数

给定一个长度为n的整数序列,以及一个整数k,用快排求出薯类的第k小的数是多少

输入:

row1是整数n和整数k

row2是n个整数

# include <iostream>
using namespace std;

const int N = 1e6+10;

int n,k;
int q[N];

// basic quick sort
void quick_sort(int q[], int l, int r){
    if(l >= r) return;
    // judge the boundary
    
    int i=l-1,j=r+1;
    int x=q[r+l >> 1];
    // initiate x, i, j
    
    while(i < j){
        do i++; 
		while(q[i]<x);
		
        do j--; 
		while(q[j]>x);
		
        if(i < j) swap(q[i],q[j]);
    }
    
    // 如果x=q[l],则必须写成j和j+1
    quick_sort(q, l, j);
    quick_sort(q, j+1, r);
}


int main(){
    cin>>n>>k;
    for(int i=0; i<n; i++){
        scanf("%d", &q[i]);
    }
    
    quick_sort(q, 0, n-1);
    
    cout<<q[k-1];
    
    return 0;
}
/*
5 3
2 4 1 5 3

3
*/

直接求解第k个数

# include <iostream>
using namespace std;

const int N = 1e6+10;

int n,k;
int q[N];

int quick_sort(int l, int r, int k){
    if(l == r) return q[l]; // 已经收敛
	
	int x = q[l],i=l-1,j=r+1;
	while(i<j){
		while(q[++i]<x);
		while(q[--j]>x);
		if(i<j) swap(q[i],q[j]);
	} 
	int len=j-l+1; // 左边数组的个数
	if(k <= len) return quick_sort(l,j,k);
	return quick_sort(j+1,r,k-len);
}


int main(){
    cin>>n>>k;
    for(int i=0; i<n; i++){
        scanf("%d", &q[i]);
    }
    
    cout<<quick_sort(0,n-1,k); // left, right, k-th
    
    return 0;
}
/*
5 3
2 4 1 5 3

3
*/

2:逆序对的数量

# include <iostream>
using namespace std;

const int N = 1e6+10;

int n,k;
int q[N],tmp[N];

typedef long long LL;

LL merge_sort(int l, int r){
	if (l>=r) return 0;
	int mid = l+r >> 1;
	LL res = merge_sort(l,mid) + merge_sort(mid+1,r);
	
	int k=0, i=l ,j=mid+1;
	while(i<=mid && j<=r){
		if(q[i]<=q[j]){
			tmp[k++]=q[i++];
		}
		else{
			tmp[k++]=q[j++];
			res += mid-i+1; // 和普通归并不一样的地方
			// 此时说明左侧当前数 是大于 右侧当前数的
			// 那么,逆序对的数量,就可以计算了
			// 右侧当前数对应的逆序对数量,就是左侧当前数到最后一个数的个数 
		}
	}
	while(i<=mid){
		tmp[k++]=q[i++];
	}
	while(j<=mid){
		tmp[k++]=q[j++];
	}
	
	// copy tmp to q
	i = l;	// for q
	j = 0;	// for tmp
	for(;i<=r;i++,j++){
		q[i]=tmp[j];
	}
	return res; 
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++)
    	cin>>q[i];
    
    cout<<merge_sort(0,n-1)<<endl;
    
    return 0;
}
/*
6
2 3 4 5 6 1

5
*/

3:三次方根

#include <iostream>
using namespace std;

const int N = 1e6+10;

int main(){
	double x;
	cin>>x;
	
	double l=-10000;
	double r=-l;
	while(r-l > 1e-8){
		double mid=(l+r)/2;
		if(mid * mid * mid >= x)
			r = mid;
		else
			l=mid;
	}
	cout<<l;
	return 0;
}
  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MorleyOlsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值