算法模板01
快速排序
- 思想:分治
确定分界点:
q[l]
/q[(l+r)/2]
/q[r]
/随机
==(难点)==调整区间:
≤x
x≥x
递归处理左右两段
暴力做法:
- 设置a[],b[]
- 对于q[l~r]:
- q[i]≤x,x->a[]
- q[i]≥x,x->b[]
- a[]->q[],b[]->q[]
优美做法:
- 设置双指针l,r
- i往右移动,直到看到≥x的数
- j往左移动,直到看到≤x的数
- swap(i,j)
- 循环,直到i,j相遇
1 | void quick_sort(int q[],int l,int r) |
归并排序 ==O(n*lgn)==
- 思想:分治
- 确定分界点mid=(l+r)/2
- 递归排序left、right
- 归并,合二为一
1 | void merge_sort(int q[],int l,int r) |
二分
- 整数二分(二分左边):
- mid=(l+r==+1==)/2//l=mid,补上+1
- if(check(mid))
- true->[mid,r]//若l=r-1,如果mid=(l+r)/2,此处死循环
- flase->[l,mid-1]
整数二分(二分右边):
mid=(l+r)/2//r=mid,无需补上+1
if(check(mid))
true->[l,mid]
flase->[mid+1,r]
高精度(位数1e6)
高精度加法
大整数存储
方式:用数组存储,==第0位存个位==(目的是方便进位)
比如,输入:123456789
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] 9 8 7 6 5 4 3 2 1 往后输入直接push_back即可
运算过程
模拟人工加法,先加个位数,进位,再加十位数……
1
2
3
4
5
6
7
8
9
10
11
12
13vector<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++){
t+=A[i];
if(i<B.size()) t+=B[i];
C.push_bzack(t%10);
t=t/10;
}
if(t) C.push_back(t);
return C;
}
高精度减法
- A≥B, 算A-B
- A<B,算-(B-A)
1 | vector<int> sub(vector<int> &A,vector<int> &B){ |
高精度乘法
适用于高精度整数*低精度整数
1 | vector<int> mul(vector<int> &A,int b){ |
高精度除法
适用于高精度整数/低精度整数
1 | vector<int> div(vector<int> &A,int b,int &r){//r通过引用传回去 |
前缀和
有一个数组a1,a2,a3,a4,a5,……
前缀和S
i=a1+a2+a3+a4+a5……+ai求法:S
i=Si+1+ai作用:可以快速求出数组里面某一段的和:S
r-Sl-1
子矩阵的和(二维前缀和)
S[i,j]的含义:
(x
1,y1),(x2,y2)这一子矩阵的和该如何计算?- S[x
2,y2]-S[x2,y1-1]-S[x1-1,y2]+S[x1-1,y1-1]
- S[x
S[i,j]如何计算?
- S[i,j]=S[i-1,j]+S[i,j-1]-S[i-1,j-1]+a[i,j]
- 按照每一行从左往右求
- 下标从1开始计算
差分
对于a1,a2,……an
构造b1,b2,……bn;
使得ai=b1+b2+……+bn;b成为a的差分,a为b的前缀和
适用于:使a[l,r]上的数字全部加上c->仅需让bl+c,br+1-c
注意:不需要插入ai,只需要看成i到i插入ai即可
差分矩阵(二位差分)
对于a[n,m],假想一个b[n,m],使得a数组为b数组的前缀和
适用于:从(x1,y1)到(x2,y2)的部分加上c,仅需b[x1,y1]+=c,b[x2+1,y1]-=c,b[x2+1,y1]-=c,b[x2+1,y2+1]+=c;
注意:不需特意构造b[i,j],只需要看成i,j到i,j插入a[i,j]即可
最长连续不重复子序列
双指针算法模板:
1 | for(int i=0,j=0;i<n;i++){ |
双指针算法用途:优化复杂度到 O(n)
位运算操作
整数n的二进制表示里面第k位数字是几
- n=15=(1111)
2
先把第k位移到个位,即n右移k位,看个位是几;
n>>k&1
- n=15=(1111)
lowbit(x)
返回x的最后一位1:
1 | x=1010; |
原理:x&(-x)
应用:求x中1的个数
离散化(整数,保序)
a[]={1,3,100,2000,500000};
映射到0,1,2,3,4
- a中可能有重复元素,需要去重
- 如何算出x在a中的下标? 用二分
适用于:数据范围很大,但是很稀疏
==去重==:
1 | alls.erase(unique(all.begin(),alls.end()),alls.end()); |
unique
:重复元素移到末尾,并且返回重复元素开始的端点
区间合并
把有交集的区间合并成为一个区间(有公共端点也合并)
- 按照区间的左端点排序
- 扫描整个区间,扫描的过程中,合并区间