基础算法板子
文章目录
1.快速排序
快速排序
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
模板:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=10000+100;
int q[N],n;
void quick_sort(int l,int r){
if(l>=r) return;
int x=q[l+r>>1],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(l,j);
quick_sort(j+1,r);
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
quick_sort(0,n-1);
for(int i=0;i<n;i++) printf("%d ",q[i]);
}
第K个数
2.归并排序
归并排序
输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5
模板:
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100000+10;
int q[N],res[N],n;
void merge_sort(int l,int r){
if(l>=r) return;
int mid=l+r>>1;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r){
if(q[i]<q[j]) res[k++]=q[i++];
else res[k++]=q[j++];
}
while(i<=mid) res[k++]=q[i++];
while(j<=r) res[k++]=q[j++];
for(i=0,j=l;j<=r;j++) q[j]=res[i++];
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&q[i]);
merge_sort(0,n-1);
for(int i=0;i<n;i++) printf("%d ",q[i]);
return 0;
}
3.二分
数的范围
输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1
模板:
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX = 100005;
int asd[MAX];
int n,q;
int find_asdl(int x){
int l=0,r=n-1;
while(l<r){
//cout<<" made in china "<<endl;
int mid=l+r>>1;
if(asd[mid]<x) l=mid+1;
else r=mid;
}
if(asd[l]==x) return l;
else return -1;
}
int find_asdr(int x){
int l=0,r=n-1;
while(l<r){
//cout<<" made in china "<<endl;
int mid=l+r+1>>1;
if(asd[mid]<=x) l=mid;
else r=mid-1;
}
if(asd[r]==x) return r;
else return -1;
}
int main(){
cin>>n>>q;
for(int i=0;i<n;i++) cin>>asd[i];
for(int i=0;i<q;i++){
int x;
cin>>x;
cout<<find_asdl(x)<<" "<<find_asdr(x)<<endl;
}
return 0;
}
数的三次方根
输入样例:
1000.00
输出样例:
10.000000
模板:
//浮点数二分查找
#include<iostream>
using namespace std;
int main(){
double n;
cin>>n;
double l=1e-4-10,r=1e4+10;
while(r-l>1e8){
double mid=(l+r)/2;
if(mid*mid*mid>n) r=mid;
else l=mid;
}
printf("%lf\n",l);
return 0;
}
4.高精度
高精度加法
输入样例:
12
23
输出样例:
35
模板:
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
const int N = 1e6 + 10;
vector<int>add(vector<int> &A,vector<int> &B){
vector<int>C;
if(A.size()<B.size()) return add(B,A);
int t=0;
for(int i=0;i<A.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);
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');
vector<int> C=add(A,B);
for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
return 0;
}
高精度减法
输入样例:
32
11
输出样例:
21
模板:
//高精度减法
#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
bool panduan(vector<int> &A,vector<int> &B){
if(A.size()!=B.size()) return A.size()>B.size();
else
{
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;
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();
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');
if(panduan(A,B)){
vector<int> C=sub(A,B);
for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
}else{
vector<int> C=sub(B,A);
printf("-");
for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
}
return 0;
}
高精度乘法
输入样例:
2
3
输出样例:
6
模板:
//高精度乘法
#include<iostream>
#include<vector>
#include<cstdio>
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;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');
vector<int> C=mul(A,b);
for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);
return 0;
}
高精度除法
输入样例:
7
2
输出样例:
3
1
模板:
//高精度除法
#include<iostream>
#include<vector>
#include<cstdio>
#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()); //这玩意好用啊 reverse 要包含 algorithm 方便后的前导 0
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;
vector<int> C=div(A,b,r);
if(C.size())
for(int i=0;i<C.size();i++) printf("%d",C[i]);
cout<<endl<<r<<endl;
return 0;
}
5.前缀和与差分
前缀和
输入样例:
5 3
2 1 3 6 4
1 2
1 3
2 4
输出样例:
3
6
10
模板:
//前缀和
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int n,m;
int a[N],s[N];
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++) s[i]=s[i-1]+a[i];
while(m--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",s[r]-s[l]);
}
return 0;
}
子矩阵的和
输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出样例:
17
27
21
模板:
#include<iostream>
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1010;
int n,m,q;
int a[N][N],s[N][N];
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]);
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,y1,x2,y2;
scanf("%d%d%d",&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;
}
差分
输入样例:
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
输出样例:
3 4 5 3 4 2
模板:
//一维差分
#include<iostream>
using namespace std;
const int N = 10010;
int n,m;
int a[N],b[N]; //b 是 a 的前缀和 a 是 b 的差分
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]); // 构造 b 使得 为 a 的差分
while(m--){
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);
}
for(int i=1;i<=n;i++) b[i]+=b[i-1]; // b 数组变成自己的前缀和
for(int i=1;i<=n;i++) printf("%d",b[i]);
return 0;
}
差分矩阵
输入样例:
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
输出样例:
2 3 4 1
4 3 4 1
2 2 2 2
模板:
//二维差分
#include<iostream>
#include<cstdio>
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][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]);
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,y1,x2,y2,c;
cin>>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++) printf("%d ",b[i][j]);
puts("");
}
return 0;
}
6.双指针算法
最长连续不重复子序列
输入样例:
5
1 2 2 3 5
输出样例:
3
模板:
//最长连续不重复子序列
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int n;
int a[N],s[N];
int main(){
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]]++;
while(s[a[i]]>1){
s[a[j]]--;
j++;
}
res=max(res,i-j+1);
}
cout<<res<<endl;
return 0;
}
数组元素的目标和
7.位运算
二进制中1的个数
输入样例:
5
1 2 3 4 5
输出样例:
1 1 2 1 2
模板:
// lowbit操作 : 返回 x 的最后一位 1
//二进制中 1 的个数
#include<iostream>
#include<cstdio>
using namespace std;
int lowbie(int x){ //lowbit x 可以返回 x 的最后一位 1
return x & -x; // & 与运算符 -x = ~x+1(取反 x +1)
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
int res=0;
while(x) x-=lowbie(x) res++;
cout<<res<<endl;
}
}
8.离散化
区间和
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
模板:
//离散化
//区间和
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 300010;
typedef pair<int,int> PII;
int n,m;
int a[N],s[N];
vector<int>alls;
vector<PII>add,query;
int find(int x){
int l=0,r=alls.size()-1;
while(l<r){
int mid=r+l>>1;
if(alls[mid]>=x) r=mid;
else l=mid+1;
}
return r+1;
}
//vector<int>::iterator unique(vector<int> &a){
// int j=0;
// for(int i=0;i<a.size();i++)
// if(!i||a[i]!=a[i-1])
// a[j++]=a[i];
//
// return a.begin()+j;
//}
int main(){
cin>>n>>m;
for(int i=0;i<n;i++){
int x,c;
cin>>x>>c;
add.push_back({x,c});
alls.push_back(x);
}
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()); //unique 返回去重后的数组最后一个元素
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;
}
9.区间合并
区间合并
输入样例:
5
1 2
2 4
5 6
7 8
7 9
输出样例:
3
模板:
//区间合并
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int N = 100010;
int n;
typedef pair<int,int>PII;
vector<PII> segs;
//双指针
void merge(vector<PII> &segs){
vector<PII> res;
sort(segs.begin(),segs.end()); //C++默认先以 first 排序再以 second 排序
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;
}
else ed=max(ed,seg.second);
if(st!=-2e9) res.push_back({st,ed});
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;
}