快速排序
void quicksort(int a[],int l,int r){
if(l>=r) return ;
int x=a[l+r>>1],i=l-1,j=r+1;
while(i<j){
do i++;while(a[i]<x);
do j--;while(a[j]>x);
if(i<j) swap(a[i],a[j]);
}
quicksort(a,l,j);
quicksort(a,j+1,r);
}
归并排序
void mergesort(int left,int right){
if(left>=right) return ;
int mid=(left+right)/2;
mergesort(left,mid);
mergesort(mid+1,right);
int i=left,j=mid+1,k=0;
while(i<=mid&&j<=right){
if(a[i]<=a[j]) b[k++]=a[i++];
else b[k++]=a[j++];
}
while(i<=mid) b[k++]=a[i++];
while(j<=right) b[k++]=a[j++];
for(int i=left,j=0;i<=right;i++,j++) a[i]=b[j];
return ;
}
二分
//整数二分
int left=l,right=r;
while(left<right){
int mid=left+right>>1;
if(check(mid)) right=mid;
else left=mid+1;
}
int left=l,right=r;
while(left<right){
int mid=left+right+1>>1;
if(check(mid)) right=mid-1;
else left=mid;
}
//浮点数二分
double l,r;
while(r-l>1e-8){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
高精度
A+B
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);
return C;
}
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();
return C;
}
A*b
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;
}
A/b
vector<int> mul(vector<int> &A,int b,int &r){
vector<int>C;
r=0;
for(int i=A.size();i>=0;i--){
r=r*10+A[i];
C.push_back(r/b);
r%=b;
}
reverse(C.begin(),C.end());//#include<algorithm>
while(C.size()>1&&C.back()==0) C.pop_back();
return C;
}
前缀和与差分
一维前缀和
a[i]+=a[i-1];
表示l到r区间的元素和:
a[r]-a[l-1];
二维前缀和
a[i][j]+=a[i][j-1]+a[i-1][j]-a[i-1][j-1];
表示(x1,y1)到(x2,y2)区间的元素和:
a[x2][y2]+a[x1-1][y1-1]-a[x1-1][y2]-a[x2][y1-1];
一维差分
a[i]=b[i]-b[i-1];
表示将序列中[l,r]之间的每个数加上c:
a[l]+=c,a[r+1]-=c;
二维差分
b[i][j]+=a[i][j];
b[i+1][j+1]+=a[i][j];
b[i][j+1]-=a[i][j];
b[i+1][j]-=a[i][j];
表示将(x1,y1)到(x2,y2)之间每个数加上c:
b[x1][y1]+=c;
b[x2+1][y2+1]+=c;
b[x1][y2+1]-=c;
b[x2+1][y1]-=c;
双指针
for(i=0,j=0;i<n;i++){
while(j<i&&check(i,j)) j++;
//......
}
位运算
把n的二进制数的第k位移动到最后一位:
n>>k;
求n的二进制数的最后一位
n&1;
求n的二进制数的第k位
n>>k&1;
lowbit(x);
表示返回x表示的二进制中最低位1对应的值
如:
x为10D,则其二进制表示为1010B
则lowbit(x)=10B=2D
实现:
int lowbit(int x){
return x&-x;
}
离散化
离散化本质上就是化大为小,把稀疏离散化简为稠密连续的一段
特点:值域大,个数少
//离散化模板:
vector<int>a;//存储所有待离散化的值
sort(a.begin(),a.end());//排序
a.erase(unique(a.begin(),a.end()),a.end());//去重
//二分出x对应的离散化的值
int find(int x){//找到第一个大于等于x的位置
int l=0,r=a.size()-1;
while(l<r){
int mid=l+r>>1;
if(a[mid]>=x) r=mid;
else l=mid+1;
}
return r+1;//映射到1,2,3,4,5,6......
}
//另一种离散化模板:
void work(int a[]){
for(int i=1;i<=n;i++) p[i]=i;
sort(p+1,p+1+n,[&](int x,int y){return a[x]<a[y];});
for(int i=1;i<=n;i++) a[p[i]]=i;
}
//另一种离散化模板:
补:lower_bound(first,last,value):
可以查找区间中第一个>=value的值,返回指向这个数的下标的迭代器
lower_bound的头文件为#include<algorithm>
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];//输入要离散化的a数组
b[i]=a[i];//b数组临时记录a的值
}
sort(a+1,a+n+1);//给a排序
int cnt=unique(a+1,a+n+1)-(a+1);//计算a中不重复的所有元素个数
for(int i=1;i<=n;i++){
b[i]=lower_bound(a+1,a+cnt+1,b[i])-(a+1)+1;//将b数组更新为离散化后的下标
}
for(int i=1;i<=n;i++) cout<<b[i]<<" ";//输出b数组
return 0;
}
区间合并
#include<algorithm>
#define x first
#define y second
const int N=1e5+5;
typedef pair<int,int>pii;
pii seg[N];
sort(seg,seg+n);
int l=seg[0].x,r=seg[0].y;
for(int i=0;i<n;i++){
if(seg[i].x<=r) r=max(r,seg[i].y);
else l=seg[i].x,r=seg[i].y;
}