acwing算法基础 模板

前言

所有题目都可以在acwing题库上搜到。

归并

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int q[N]={};
int tmp[N]={};
void merge(int q[],int l,int r){
    if(l==r) return;
    int mid=l+r>>1;
    merge(q,l,mid),merge(q,mid+1,r);
    
    int i=l,j=mid+1,k=0;
    while(i<=mid&&j<=r){
        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++];
    for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
    return ;
}
int main(){
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    merge(q,0,n-1);
    for(int i=0;i<n;i++) printf("%d ",q[i]);
    return 0;
}
逆序对的数量
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int q[N],tmp[N];
long long num1=0;
void merge(int l,int r){
    if(l==r) return ;
    int mid=l+r>>1;
    int i=l,j=mid+1,k=0;
    merge(l,mid),merge(mid+1,r);
    while(i<=mid&&j<=r){
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else{ 
            tmp[k++]=q[j++];
            num1+=mid-i+1;//有多少个是比当前的qj大的
        }
    }
    while(i<=mid) tmp[k++]=q[i++];
    while(j<=r) tmp[k++]=q[j++];
    for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
    return ;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    merge(0,n-1);
    printf("%lld",num1);
    return 0;
}
超快速排序
#include<bits/stdc++.h>
using namespace std;
const int N=500010;
int q[N],tmp[N];
long long num=0;
void merge(int l,int r){
    if(l==r) return ;
    int mid=l+r>>1;
    merge(l,mid),merge(mid+1,r);
    int i=l,j=mid+1,k=0;
    while(i<=mid&&j<=r){
        if(q[i]<=q[j]) tmp[k++]=q[i++];
        else{
            tmp[k++]=q[j++];
            num+=mid-i+1;
        }
    }
    while(i<=mid) tmp[k++]=q[i++];
    while(j<=r) tmp[k++]=q[j++];
    for(int i=l,j=0;i<=r;i++,j++) q[i]=tmp[j];
    return;
}
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        if(n==0) continue;
        else{
            for(int i=0;i<n;i++) scanf("%d",&q[i]);
            num=0;
            merge(0,n-1);
            printf("%lld\n",num);
        }
    }
    return 0;
}

二分

二分的用途不仅仅简单的用于排好序列的数组,还有可拓展的空间,二分的实质在于缩小搜索的范围,算是一种简单的剪枝。
更加深刻的说法,或者更加准确来说,二分应该满足的是二分性,而不是单调性。即某个节点的左侧都满足(不满足),右侧都不满足(都满足)。

特殊排序(交互式)
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.

class Solution {
public:
    vector<int> specialSort(int N) {
        vector<int> res;
        res.push_back(1);
        for(int i=2;i<=N;i++){
            int l=0,r=res.size()-1;
            while(l<r){
                int mid=l+r+1>>1;
                if(compare(res[mid],i)) l=mid;
                else r=mid-1;
            }
            res.push_back(i);
            for(int j=res.size()-2;j>r;j--) swap(res[j],res[j+1]);
            if(compare(i,res[r])) swap(res[r],res[r+1]);
        }
        return res;
    }
};

另一种更加简洁的写法

class Solution {
public:
    vector<int> specialSort(int N) {
        vector<int> res;
        res.push_back(1);
        for(int i = 2;i <= N;i++){
            int l = 0,r = res.size() - 1;
            while(l <= r){
                int mid = l + r >> 1;
                if(compare(res[mid],i)) l = mid + 1;
                else    r = mid - 1;
            }
            res.push_back(i);
            for(int j = res.size() - 2;j > r;j--)   swap(res[j],res[j + 1]);
        }
        return res;
    }
};
最佳牛围栏

体现出是二分性,而不是单调性的例子(或许同时满足了。

#include<bits/stdc++.h>
using namespace std;
const int N =100010;
double sum[N];
int q[N];
int n,m;
bool check(double avg){
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+q[i]-avg;
    double minv=0;
    for(int i=0,j=m;j<=n;j++,i++){
        minv=min(minv,sum[i]);
        if(sum[j]>=minv) return true;
    }
    return false;
} 
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&q[i]);
    
    double l=0,r=2000;
    while(r-l>1e-5){
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%d\n",int(r*1000));
    return 0;
}
数字的三次方根

二分的直白描述

#include<bits/stdc++.h>
using namespace std;
int N =10010;
int main(){
    double n;scanf("%lf",&n);
    double l=-N,r=N;
    while(r-l>1e-8){
        double mid=(l+r)/2;
        if(mid*mid*mid<=n) l=mid;
        else r=mid;
    }
    printf("%lf",r);
    return 0;
}

前缀和

朴素前缀和
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=100010;
int q[N];
int sum[N];
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&q[i]);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+q[i];
    while(m--){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",sum[r]-sum[l-1]);
    }
    return 0;
}
子矩阵的和
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const int N=1001;
int q[N][N],sum[N][N];

int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&q[i][j]);
            sum[i][j]=sum[i-1][j]+sum[i][j-1]+q[i][j]-sum[i-1][j-1];
        }
    }
    while(k--){
        int l,r,ll,rr;
        scanf("%d%d%d%d",&l,&r,&ll,&rr);
        printf("%d\n",sum[ll][rr]+sum[l-1][r-1]-sum[l-1][rr]-sum[ll][r-1]);
    }
    return 0;
}
差分
#include<bits/stdc++.h>
using namespace std;
int n,m;
const int N=100010;
int q[N];
void insert(int l,int r,int c){
    q[l]+=c;
    q[r+1]-=c;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int tmp;
        scanf("%d",&tmp);
        insert(i,i,tmp);
    }
    while(m--){
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        insert(l,r,c);
    }
    int sum=q[0];
    for(int i=1;i<=n;i++){
        sum+=q[i];
        printf("%d ",sum);
    }
}
二维差分
#include<iostream>
using namespace std;
const int N=1010;
int n,m,q;
int a[N][N],b[N][N];
void insert(int x1,int y1,int x2,int y2,int c){
    b[x1][y1]+=c;
    b[x2+1][y2+1]+=c;
    b[x2+1][y1]-=c;
    b[x1][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]);
            insert(i,j,i,j,a[i][j]);
        }  
    while(q--){
        int x1,x2,y1,y2,c;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
        insert(x1,y1,x2,y2,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];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            printf("%d ",b[i][j]);
        }
        printf("\n");
    }
    return 0;
}

双指针算法

双指针算法覆盖范围极其广,快排实际上就是一种双指针算法,需要满足单调性才可以使用(答案的单调性。

最长不下降子序列
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int q[N],s[N];
int main(){
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    int ans=0;
    for(int i=0,j=0;i<n;i++){
        s[q[i]]++;
        while(s[q[i]]>1){
            s[q[j]]--;
            j++;
        }
        ans=max(ans,i-j+1);
    }
    cout<<ans;
    return 0;
}
数组元素的目标和
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const int N=100010;
int a[N],b[N];
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    for(int i=0;i<m;i++) scanf("%d",&b[i]);
    for(int i=0,j=m-1;i<n;i++){
        while(j>=0&&a[i]+b[j]>k) j--;
        if(a[i]+b[j]==k){
            cout<<i<<" "<<j<<endl;
        }
    }
    return 0;
}

快排:

实际上就是双指针算法的一种

经典快排
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int q[N]={};

//核心
void quick_sort(int q[],int l,int r){
    if(l>=r) return ;
    int x=q[(l+r)/2],i=l-1,j=r+1;
    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);
    return ;
}
//核心

int main(){
    int n;cin>>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;
}
第k个数字
#include<iostream>
using namespace std;
const int N=100010;
int n;
int q[N];
int quick_sort(int l,int r,int k){
    if(l==r) return q[l];
    int i=l-1,j=r+1,x=q[l+r>>1];
    while(i<j){
        while(q[++i]<x);
        while(q[--j]>x);//注意是大于和小于,否则将会内存超限
        if(i<j) swap(q[i],q[j]);
    }
    int sl=j-l+1;
    if(k<=sl) return quick_sort(l,j,k);
    return quick_sort(j+1,r,k-sl);
}
int main()
{
    int k;
    cin>>n>>k;
    for(int i=0;i<n;i++) scanf("%d",&q[i]);
    cout<<quick_sort(0,n-1,k);
    return 0;
}

位运算

64位整数乘法(快速幂)
#include<bits/stdc++.h>
using namespace std;
long long res;
int main(){
    long long a,b,c;scanf("%lld%lld%lld",&a,&b,&c);
    while(b){
        if(b&1) res=(res+a)%c;
        b>>=1;
        a=a*2%c;
    }
    cout<<res;
    return 0;
}
二进制中1的个数
#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;scanf("%d",&n);
    for(int i=0;i<n;i++){
        int tmp;scanf("%d",&tmp);
        int ans=0;
        while(tmp!=0){
            if(tmp%2!=0) ans++;
            tmp>>=1;
        }
        cout<<ans<<" ";
    }
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值