ACwing算法基础课——基础算法

Acwing——https://www.acwing.com/

快排

#include<iostream>
using namespace std;
const int N = 100001;
int q[N];
void quick_sort(int q[],int l,int r){
    if(l>=r) return;
    
    int i=l-1,j=r+1;
    int x=q[(l+r)/2];
    while(i<j){
        do i++;while(q[i]<x);
        do j--;while(q[j]>x);
        if(i<j) swap(q[i],q[j]);
    }
    quick_sort(q,l,j),quick_sort(q,j+1,r);
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>q[i];
    
    quick_sort(q,0,n-1);
    
    for(int i=0;i<n;i++) cout<<q[i]<<" ";
    
    return 0;
}

归并排序

#include<iostream>
using namespace std;
const int N=100001;
int q[N],temp[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;
    while(i<=mid&&j<=r){
        if(q[i]<=q[j]) temp[k++]=q[i++];
        else temp[k++]=q[j++];
    }
    while(i<=mid) temp[k++]=q[i++];
    while(j<=r) temp[k++]=q[j++];
    for(i=l,k=0;i<=r;i++,k++) q[i]=temp[k];
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>q[i];
    
    merge_sort(q,0,n-1);
    
    for(int i=0;i<n;i++) cout<<q[i]<<" ";
    
    return 0;
}

逆序对的数量

给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。

逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。

输入格式
第一行包含整数 n,表示数列的长度。

第二行包含 n 个整数,表示整个数列。

输出格式
输出一个整数,表示逆序对的个数。

#include<iostream>
using namespace std;
const int N=100001;
int q[N],temp[N];
long long merge_sort(int q[],int l,int r){
    if(l>=r) return 0;
    
    int mid=l+r >>1;
    long long res=merge_sort(q,l,mid)+merge_sort(q,mid+1,r);
    
    int k=0,i=l,j=mid+1;
    while(i<=mid&&j<=r){
        if(q[i]<=q[j]) temp[k++]=q[i++];  //<=因为只有右边的小于左边才算逆序对
        else{
            temp[k++]=q[j++];
            res+=mid-i+1;
        }
    }
    while(i<=mid) temp[k++]=q[i++];
    while(j<=r)temp[k++]=q[j++];
    
    for(i=l,k=0;i<=r;i++,k++) q[i]=temp[k];
    return res;
}

int main(){
    int n;
    long long p_num;
    cin>>n;
    for(int i=0;i<n;i++) cin>>q[i];
    p_num=merge_sort(q,0,n-1);
    cout<<p_num;
    return 0;
}

二分

整数二分

// 给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询
// 对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
// 如果数组中不存在该元素,则返回 -1 -1。
// 输入格式
// 第一行包含整数 n 和 q,表示数组长度和询问个数。
// 第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。
// 接下来 q 行,每行包含一个整数 k,表示一个询问元素。
// 输出格式
// 共 q 行,
// 如果数组中不存在该元素,则返回 -1 -1。
#include<iostream>
using namespace std;
const int N=100001;
int a[N];
int main(){
    int n,q;
    cin>>n>>q;
    for(int i=0;i<n;i++) cin>>a[i];
    while(q--){
        int x;
        cin>>x;
        int l=0,r=n-1;
        
        //找到左边的数的位置,用 >=x
        while(l<r){
            int mid=l+r>>1;
            if(a[mid]>=x) r=mid;
            else l=mid+1;
        }
        if(a[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(a[mid]<=x) l=mid;
                else r=mid-1;
            }
            cout<<l<<endl;
        }
    }
    return 0;
}

浮点数二分

// 给定一个浮点数 n,求它的三次方根。
#include<iostream>
using namespace std;
int main(){
    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);
    return 0;
}

高精

高精加

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

vector<int> add(vector<int>&A,vector<int>&B){
    // if(A.size()<B.size()) return add(B,A);
    vector<int> C;
    int t=0;//进位;
    for(int i=0;i<A.size()||i<B.size();i++){
        // t+=A[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(t);//最后还要加一个判断,看循环完成之后有没有进位
    return C; //返回的C是vector<int> 类型。
}

int main(){
    string a,b;
    vector<int> A,B;
    cin>>a>>b;
    //把大整数倒过来存到vector里面,高精都是这样存数据。
    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');
    
    vector<int> C=add(A,B);//计算结果。
    //倒着输出结果
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    return 0;
}

高精减

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

bool cmp(vector<int> &A,vector<int> &B){
    if(A.size()!=B.size()) return A.size()>B.size();
    else{//A和B长度相同
        for(int i=A.size()-1;i>=0;i--){
            if(A[i]!=B[i]) return A[i]>B[i];
        }
        return true;
    }
}

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; //A[i]减去上一位的进位
        if(i<B.size()) t-=B[i];  //减去B[i]
        C.push_back((t+10)%10);//可能有不够减借位的情况,所以要加上10再模10
        if(t<0) t=1;
        else t=0;
    }
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}



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

高精乘

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


vector<int> mul(vector<int> &A,int b){
    vector<int> C;
    int t=0;//进位
    for(int i=0;i<A.size()||t>0;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;
}


int main(){
    string a;
    int b;
    cin>>a>>b;
    vector<int> A,C;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    
    C=mul(A,b);
    
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    
    return 0;
}

高精除

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

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;
}

int main(){
    string a;
    int b,r;//b是除数,r是余数
    vector<int> A,C;
    cin>>a>>b;
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    
    C=div(A,b,r);
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    cout<<endl<<r;
    return 0;
}

前缀和差分

前缀和

#include<iostream>
using namespace std;
const int N=100001;
int q[N],s[N];
int main(){
    int n,m;
    q[0]=0;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>q[i];
        s[i]=s[i-1]+q[i];
    }
    for(int i=0;i<m;i++){
        int l,r;
        cin>>l>>r;//sacnf读的快
        cout<<s[r]-s[l-1]<<endl;
    }
    return 0;
}

子矩阵的和

// 输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,
// 表示一个子矩阵的左上角坐标和右下角坐标。
// 对于每个询问输出子矩阵中所有数的和。

#include<iostream>
using namespace std;
const int N=1001;
int a[N][N],s[N][N];
int main(){
    int n,m,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][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;
        cin>>x1>>y1>>x2>>y2;
        cout<<s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]<<endl;
    }
    return 0;
}

差分

// 输入一个长度为 n 的整数序列。

// 接下来输入 m 个操作,每个操作包含三个整数 l,r,c,
//表示将序列中 [l,r] 之间的每个数加上 c。

// 请你输出进行完所有操作后的序列。
#include<iostream>
using namespace std;
const int N=100001;
int a[N],b[N];
void insert(int b[],int l,int r,int c)
{
    b[l]+=c;
    b[r+1]-=c;
}

int main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        insert(b,i,i,a[i]);
    }
    while(m--){
        int l,r,c;
        cin>>l>>r>>c;
        insert(b,l,r,c);
    }
    for(int i=1;i<=n;i++) {
        b[i]+=b[i-1];
        cout<<b[i]<<" ";
    }
    return 0;
}

差分矩阵

// 输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,
// 其中 (x1,y1) 和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。

// 每个操作都要将选中的子矩阵中的每个元素的值加上 c。

// 请你将进行完所有操作后的矩阵输出。

#include<iostream>
using namespace std;
const int N=1002;
int a[N][N],b[N][N];
void insert(int b[N][N],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(){
    int n,m,q;
    cin>>n>>m>>q;
    // 接下来 n 行,每行包含 m 个整数,表示整数矩阵。
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
            insert(b,i,j,i,j,a[i][j]);
        }
    }
    // 接下来 q 行,每行包含 5 个整数 x1,y1,x2,y2,c,表示一个操作。
    while(q--){
        int x1,y1,x2,y2,c;
        cin>>x1>>y1>>x2>>y2>>c;
        insert(b,x1,y1,x2,y2,c);
    }
    // 共 n 行,每行 m 个整数,表示所有操作进行完毕后的最终矩阵。
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a[i][j]=b[i][j];
            a[i][j]+= a[i-1][j]+a[i][j-1]-a[i-1][j-1];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

双指针算法

位运算

// 给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。
#include<iostream>
using namespace std;
const int N=100001;
int a[N];
int lowbit(int x){
    return x&(-x);
}
int main(){
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i];
        int ans=0;
        while(a[i]) a[i]-=lowbit(a[i]),ans++;
        cout<<ans<<" ";
    }
    return 0;
}

离散化

区间和

// 假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
// 现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
// 接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
// 输入格式
// 第一行包含两个整数 n 和 m。
// 接下来 n 行,每行包含两个整数 x 和 c。
// 再接下来 m 行,每行包含两个整数 l 和 r。

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

const int N=300001;
int a[N],s[N];
vector<int> alls;//需要离散化的数组
vector<pair<int,int>> add,query;

int find(int x) //找到x在alls中的位置,//根据数的大小分配下标(也就是位置)
{
    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(){
    int m,n;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int x,c;
        cin>>x>>c;
        add.push_back({x,c});//在x的位置加上c
        
        alls.push_back(x);//把x加入要离散化的数组
    }
    
    //m个询问
    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);
    }
    
    //去重
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(),alls.end()),alls.end());
    
    //处理插入
    for(auto item : add){
        int x=find(item.first);
        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;
}

区间合并

// 给定 n 个区间 [li,ri],要求合并所有有交集的区间。
// 注意如果在端点处相交,也算有交集。
// 输出合并完成后的区间个数。
// 例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。
// 输入格式
// 第一行包含整数 n。
// 接下来 n 行,每行包含两个整数 l 和 r。
// 输出格式
// 共一行,包含一个整数,表示合并区间完成后的区间个数。

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

const int N=100001;
vector<pair<int,int>> segs;

void merge(vector<pair<int,int>> &segs){
    vector<pair<int,int>> res;
    sort(segs.begin(),segs.end());
    
    int st=-2e9,ed=-2e9;
    for(auto seg:segs){
        if(ed<seg.first){
            //两个区间没有交集部分,就把当前这个区间输出,然后操作下一个区间
            if(st!=-2e9) res.push_back({st,ed});
            st=seg.first,ed=seg.second;//更新st和ed
        }
        else ed=max(ed,seg.second);//合并两个有交集的区间
    }
    if(st!=-2e9) res.push_back({st,ed});//
    
    segs=res;
}

int main(){
    int n;
    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;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: acwing算法基础课是一门针对算法学习的在线课程,在这门课程中,学生可以系统地学习和掌握算法基础知识,提高编程水平。为了方便学生学习,acwing提供了网盘服务。 acwing算法基础课网盘是一个用于存储课程资源的平台。通过这个网盘,学生可以下载课程讲义、代码模板以及补充材料等。这些资源都经过精心整理,供学生们参考和学习。 网盘中的资源是按照课程章节进行分类的,学生可以根据自己的学习需要,选择性地下载所需的资料。同时,网盘还提供了搜索功能,方便学生快速定位和获取所需资料。 acwing算法基础课网盘的使用对于学生们的学习非常有帮助。通过下载和学习这些资源,学生们可以更好地理解课程内容,加深对算法的理解。此外,学生们还可以通过研究代码模板,学习优秀的编程思想和技巧,提高自己的编程能力。 总之,acwing算法基础课网盘是一项非常便利和实用的服务,为学生们提供了更加全面和深入的学习资源,帮助他们更好地掌握和运用算法知识。 ### 回答2: acwing算法基础课是一门优质的算法学习资源,其中的课程内容丰富多样,涵盖了算法基础知识、数据结构、动态规划、图论等等。很多学习者都认为这门课程对他们的算法学习有很大的帮助。 网盘是指以网络为媒介,提供文件存储和下载服务的云存储平台。acwing算法基础课也提供了网盘服务,方便学习者下载课程资料并进行学习。 通过acwing算法基础课网盘,学习者可以方便地获取到课程的各种学习资料,包括讲义、习题集、代码示例等。这些资料可以帮助学习者更好地理解和掌握课程的内容。此外,网盘还提供了上传和分享功能,学习者可以将自己的学习心得、代码等资料分享给其他学习者,促进学习者之间的互相学习和交流。 acwing算法基础课网盘的优点不仅仅是方便快捷的下载和分享功能,还包括安全可靠的存储环境。学习者可以放心地将自己的学习资料上传到网盘进行备份,减少数据丢失的风险。同时,网盘还提供了多种存储空间容量的选择,满足学习者不同的需求。 总的来说,acwing算法基础课网盘为学习者提供了方便、安全和多样化的学习资源下载和分享服务,为学习者的算法学习和进步提供了有力的支持。如果你对算法感兴趣,我推荐你去尝试一下这门精彩的课程!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值