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


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

    快排

    #include
    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;
    }
    
    • 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

    归并排序

    #include
    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;
    }
    
    • 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

    逆序对的数量

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

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

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

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

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

    #include
    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;
    }
    
    • 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

    二分

    整数二分

    // 给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询
    // 对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
    // 如果数组中不存在该元素,则返回 -1 -1。
    // 输入格式
    // 第一行包含整数 n 和 q,表示数组长度和询问个数。
    // 第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。
    // 接下来 q 行,每行包含一个整数 k,表示一个询问元素。
    // 输出格式
    // 共 q 行,
    // 如果数组中不存在该元素,则返回 -1 -1。
    #include
    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;
    }
    
    
    • 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

    浮点数二分

    // 给定一个浮点数 n,求它的三次方根。
    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    高精

    高精加

    #include
    #include
    using namespace std;
    
    vector<int> add(vector<int>&A,vector<int>&B){
        // if(A.size()
        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 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;
    }
    
    • 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

    高精减

    #include 
    #include 
    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;
    }
    
    • 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

    高精乘

    #include
    #include 
    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;
    }
    
    • 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

    高精除

    #include
    #include 
    #include
    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;
    }
    
    • 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

    前缀和差分

    前缀和

    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    子矩阵的和

    // 输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,
    // 表示一个子矩阵的左上角坐标和右下角坐标。
    // 对于每个询问输出子矩阵中所有数的和。
    
    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    差分

    // 输入一个长度为 n 的整数序列。
    
    // 接下来输入 m 个操作,每个操作包含三个整数 l,r,c,
    //表示将序列中 [l,r] 之间的每个数加上 c。
    
    // 请你输出进行完所有操作后的序列。
    #include
    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;
    }
    
    • 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

    差分矩阵

    // 输入一个 n 行 m 列的整数矩阵,再输入 q 个操作,每个操作包含五个整数 x1,y1,x2,y2,c,
    // 其中 (x1,y1) 和 (x2,y2) 表示一个子矩阵的左上角坐标和右下角坐标。
    
    // 每个操作都要将选中的子矩阵中的每个元素的值加上 c。
    
    // 请你将进行完所有操作后的矩阵输出。
    
    #include
    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;
    }
    
    • 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

    双指针算法

    位运算

    // 给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。
    #include
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    离散化

    区间和

    // 假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
    // 现在,我们首先进行 n 次操作,每次操作将某一位置 x 上的数加 c。
    // 接下来,进行 m 次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。
    // 输入格式
    // 第一行包含两个整数 n 和 m。
    // 接下来 n 行,每行包含两个整数 x 和 c。
    // 再接下来 m 行,每行包含两个整数 l 和 r。
    
    #include
    #include
    #include 
    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;
    }
    
    • 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
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    区间合并

    // 给定 n 个区间 [li,ri],要求合并所有有交集的区间。
    // 注意如果在端点处相交,也算有交集。
    // 输出合并完成后的区间个数。
    // 例如:[1,3] 和 [2,6] 可以合并为一个区间 [1,6]。
    // 输入格式
    // 第一行包含整数 n。
    // 接下来 n 行,每行包含两个整数 l 和 r。
    // 输出格式
    // 共一行,包含一个整数,表示合并区间完成后的区间个数。
    
    #include
    #include 
    #include
    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
    • 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
  • 相关阅读:
    勇夺2022上半年新势力造车销冠的小鹏汽车有护城河吗?
    通用HttpClient封装
    SpringBoot工程启动顺序以及自定义监听
    faker.js 创建者希望 GitHub 恢复他的权利;微软公布 VS Code 2022 年路线图;Java 18 的新特性 | 开源日报
    【STM32】认识库函数引脚GPIO开启时钟,需要初始化的结构体GPIOMode_TypeDef
    Java 进阶多线程(二)
    简易基本MyBatis语句书写模板-续更中
    私域流量对企业的好处
    ubuntu18.04 报错:fatal error: execution
    Nginx反向代理配置POST请求的nginx.conf相关配置
  • 原文地址:https://blog.csdn.net/astruggle___/article/details/127871444