这里的python全是python3的
力求快、准、狠、短
基础算法
#快速排序
O(nlogn)
----c++版
https://www.acwing.com/problem/content/787/
#include<iostream>
using namespace std;
const int N = 1e6+10;
int a[N];
void qs(int q[], 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]);
}
qs(q, l, j);
qs(q, j+1, r);
}
int main(){
int n;scanf("%d", &n);
for(int i=1;i<=n;i++)scanf("%d", &a[i]);
qs(a, 1, n);
for(int i=1;i<=n;i++)printf("%d ", a[i]);
return 0;
}
----python版
def swap(t1,t2):
return t2,t1
def qs(c,l,r):
if(l>=r): return
x=c[(l+r)//2]
i=l-1
j=r+1
while(i<j):
while True:
i+=1
if(c[i]>=x):
break
while True:
j-=1
if(c[j]<=x):
break
if(i<j):
#c[i],c[j]=c[j],c[i]
c[i],c[j]=swap(c[i],c[j])
qs(c,l,j)
qs(c,j+1,r)
c=[1,4,6,2,7,4,7,9,4,8]
qs(c,0,9)
print(c)
#c[0],c[9]=swap(c[0],c[9])
#print(c)
#归并排序
可以用来解决逆序对的问题
O(nlogn)
----c++版
https://www.acwing.com/problem/content/789/
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],tmp[N];
void ms(int q[], int l, int r){
if(l>=r)return;
int mid = r+l>>1;
ms(q, l, mid);ms(q, mid+1, r);
int k=0,i=l,j=mid+1;
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(i=0,j=l;j<=r;i++,j++)q[j]=tmp[i];
}
int main(){
int n;scanf("%d", &n);
for(int i=1;i<=n;i++)scanf("%d", &a[i]);
ms(a,1,n);
for(int i=1;i<=n;i++)printf("%d ", a[i]);
return 0;
}
----python版
a = [66,11,45,79,79,4,35,987,10,0,54,3]
tmp = len(a)*[0]
def ms(q, l, r):
if l >= r:
return
mid = (l+r)//2
ms(q, l, mid); ms(q, mid+1, r)
k = 0
i = l
j = mid+1
while (i <= mid) and (j <= r):
if q[i] <= q[j]:
tmp[k] = q[i]
k += 1; i += 1
else:
tmp[k] = q[j]
k += 1; j += 1
while i <= mid:
tmp[k] = q[i]
k += 1; i += 1
while j <= r:
tmp[k] = q[j]
k += 1; j += 1
for i in range(l, r+1):
q[i] = tmp[i-l]
# 下标
ms(a, 0, len(a)-1)
print(a)
----python版2
n = int(input())
list1 = list(map(int, input().split()))
def merge_sort(list1):
if len(list1) <= 1:
return
mid = len(list1) // 2
L = list1[:mid]
R = list1[mid:]
merge_sort(L)
merge_sort(R)
i = j = k = 0
while i < len(L) and j < len(R):
if L[i] <= R[j]:
list1[k] = L[i]
i += 1
else:
list1[k] = R[j]
j += 1
k += 1
while i < len(L):
list1[k] = L[i]
k += 1
i += 1
while j < len(R):
list1[k] = R[j]
k += 1
j += 1
if __name__ == "__main__":
merge_sort(list1)
for i in list1:
print(i, end=" ")
作者:肆十一
链接:https://www.acwing.com/solution/content/4628/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
#整数二分查找
O(log n)
----c++版
https://www.acwing.com/problem/content/791/
找右 +1 <= 提l -1
#include<iostream>
using namespace std;
const int N=1e6+10;
int n,m;
int a[N];
int main()
{
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
while(m--)
{
int x;scanf("%d",&x);
int l=1,r=n;
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-1<<" ";
l=1,r=n;
while(l<r){
int mid=l+r+1>>1;
if(a[mid]<=x)l=mid;
else r=mid-1;
}
cout<<l-1<<endl;
}
}
return 0;
}
----python版
q = [1,2,3,4,4,5,5,6,6,7,7,8,9]
def bs_left(c, l, r, x):
while l < r:
mid = (l+r)//2
if c[mid-1] >= x:
r = mid
else:
l = mid+1
return l-1
def bs_right(c, l, r, x):
while l < r:
mid = (l+r+1)//2
if c[mid-1] <= x:
l = mid
else:
r = mid-1
return l-1
# 这个没写没找到的情况
for i in range(4, 6):
print(bs_left(q, 1, len(q), i), bs_right(q, 1, len(q), i))
----python版2
def bsearch_first(data, k):
l, r = 0, len(data)-1
while l < r:
mid = l + r >> 1
if data[mid] >= k:
r = mid
else:
l = mid + 1
if data[l] != k: # 不存在,返回-1
return -1
return l
def bsearch_last(data, k):
l, r = 0, len(data)-1
while l < r:
mid = l + r + 1 >> 1
if data[mid] <= k:
l = mid
else:
r = mid - 1
if data[l] != k: # 不存在,返回-1
return -1
return l
if __name__ == '__main__':
n, m = map(int, input().split())
data = list(map(int, input().split()))
while m:
x = int(input())
first = bsearch_first(data, x)
last = bsearch_last(data, x)
print(first, last)
m -= 1
作者:WakeUp
链接:https://www.acwing.com/solution/content/6226/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
#浮点数二分查找
https://www.acwing.com/problem/content/792/
----c++版
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
double x;cin>>x;
double l=0,r=x;
while(fabs(l-r)>1e-8){
double mid=(l+r)/2;
if(fabs(mid*mid*mid)>=fabs(x))r=mid;//可能是负数
else l=mid;
}
printf("%.6f",l);
}
#c++高精度算法
----基于面向对象的实现
https://blog.csdn.net/lafea/article/details/108935683
----高精度加法
https://www.acwing.com/problem/content/793/
//用vector实现
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
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++){
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');
auto c=add(A,B);
for(int i=c.size()-1;i>=0;i--)printf("%d", c[i]);
return 0;
}
----高精度减法
https://www.acwing.com/problem/content/794/
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
bool cmp(vector<int> &a, vector<int> &b)
{
if(a.size()!=b.size())return a.size()>b.size();
for(int i=a.size();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');
vector<int> C;
if(cmp(A, B)) C=sub(A, B);
else cout<<'-',C=sub(B, A);
for(int i=C.size()-1;i>=0;i--)printf("%d", C[i]);
return 0;
}
----高精度乘法
大数乘小数
https://www.acwing.com/problem/content/795/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
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;
}
while(c.size()>1&&c.back()==0)c.pop_back();
return c;
}
int main(){
string a;int b;vector<int>A;
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
auto c=mul(A,b);
for(int i=c.size()-1;i>=0;i--)printf("%d", c[i]);
return 0;
}
大数乘大数(带负数)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> multi(vector<int>& a, vector<int>& b) {
vector<int> c(a.size()+b.size());
int t = 0;
for (int i = 0; i < a.size(); i++)
for (int j = 0; j < b.size(); j++) {
c[i + j] += a[i] * b[j];//乘法原理
}
for(int i=0;i<c.size();i++)
if (c[i] > 9) {
c[i + 1] += c[i] / 10;//进位
c[i] %= 10;
}
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');
int s = 1;
if (A.back() == '-'-'0')
s *= -1, A.pop_back();
if (B.back() == '-'-'0')
s *= -1, B.pop_back();
auto c = multi(A, B);
if (s == -1&&(c.size()!=1&&c[0]!=0))cout << '-';
for (int i = c.size() - 1; i >= 0; i--)cout << c[i];
return 0;
}
----高精度除法
大数除以小数
https://www.acwing.com/problem/content/796/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
vector<int> del(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(){
vector<int>A;string a;int b,r;
cin>>a>>b;
for(int i=a.size()-1;i>=0;i--)A.push_back(a[i]-'0');
auto c=del(A, b, r);
for(int i=c.size()-1;i>=0;i--)printf("%d",c[i]);
cout<<endl<<r;
return 0;
}
#前缀和与差分
多见于区间操作
差分数组–前缀和–》原数组
原数组《–差分–前缀和数组
差分是前缀和的逆运算
##前缀和
----c++版
https://www.acwing.com/problem/content/797/
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],s[N];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);//注意要从一开始
for(int i=1;i<=n;i++)s[i]+=a[i]+s[i-1];
while(m--){
int l,r;scanf("%d%d",&l,&r);
int t=s[r]-s[l-1];
printf("%d\n",t);
}
return 0;
}
##子矩阵的和
----c++版
https://www.acwing.com/problem/content/798/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=2e6+10;
int a[1010][1010],s[1010][1010];
int main(){
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
//注意也从1开始
scanf("%d",&a[i][j]);
s[i][j]=s[i-1][j]+s[i][j-1]+a[i][j]-s[i-1][j-1];
}
}
while(q--){
int x1,x2,y1,y2;
scanf("%d%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;
}
##差分
----c++版
https://www.acwing.com/problem/content/799/
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int a[N],d[N];
void insert(int &l,int &r,int &c){
d[l]+=c;
d[r+1]-=c;
}//主要是插入操作
int main(){
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);//注意也要从1开始
d[0]=0;
for(int i=1;i<=n;i++)d[i]=a[i]-a[i-1];
while(m--){
int l,r,c;scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);
}
for(int i=1;i<=n;i++)a[i]=a[i-1]+d[i],printf("%d ",a[i]);
return 0;
}
##差分矩阵
----c++版
https://www.acwing.com/problem/content/800/
差分矩阵中的每一个单元表示前面所有抬升的阶数和,还要在抬升几阶才到原数组的值
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[1010][1010],d[1010][1010];
void op(int &x1,int &y1,int &x2,int &y2,int &c){
d[x1][y1]+=c;
d[x2+1][y1]-=c;
d[x1][y2+1]-=c;
d[x2+1][y2+1]+=c;//右下角的长方块被抬高了
}//核心操作还是插入
int main(){
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int t;scanf("%d",&t);
op(i,j,i,j,t);
}
while(q--){
int x1,x2,y1,y2,c;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&c);
op(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
d[i][j]+=d[i-1][j]+d[i][j-1]-d[i-1][j-1];//做一个前缀和即可得原数组
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d ",d[i][j]);
}printf("\n");
}
return 0;
}
#双指针算法
如尺取法等
##最长连续不重复子列
----c++版
https://www.acwing.com/problem/content/801/
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int a[N],s[N];
int main(){
int n;cin>>n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int j=0,m=0;
for(int i=1;i<=n;i++){
s[a[i]]++;
while(s[a[i]]>1){//只要大于一,就说明有重复了!
s[a[j]]--;
j++;
}
m=max(m,i-j+1);//每次j移到重复元素的后一位上
}
cout<<m;
return 0;
}
##数组元素目标和
----c++版
https://www.acwing.com/problem/content/802/
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],b[N];
int main(){
int n,m,x;cin>>n>>m>>x;
for(int i=0;i<n;i++)scanf("%d",&a[i]);
for(int i=0;i<m;i++)scanf("%d",&b[i]);
int i=0,j=m-1;
while(i<n&&j>=0){
if(a[i]+b[j]>x)
j--;
else if(a[i]+b[j]<x)
i++;
else{
printf("%d %d",i,j);
break;
}
}
return 0;
}
#位运算算法
##二进制表示中1的个数
https://www.acwing.com/problem/content/803/
----c++版1
#include<iostream>
using namespace std;
int main(){
int n;cin>>n;
while(n--){
int t,ans=0;scanf("%d",&t);
while(t){
if(t&1){
ans++;
}
t>>=1;
}printf("%d ",ans);
}
return 0;
}
----c++版2(含lowbit操作)
#include<iostream>
using namespace std;
int lowbit(int q){//返回二进制表示的最右边的1所表示的数
return q&(-q);
}
int main(){
int n;cin>>n;
while(n--){
int q,ans=0;scanf("%d",&q);
while(q)q-=lowbit(q),ans++;
printf("%d ",ans);
}
return 0;
}
#离散化
##求区间和
----c++版
https://www.acwing.com/problem/content/804/
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef pair<int,int> pll;
const int N=3e6+10;//一般开2-3倍
int n,m;
int a[N],s[N];
vector<int>alls;//所有被用到的坐标
vector<pll>add,query;//存所有要加的值和将要询问的区间
int find(int x){//找x是所有用到坐标的第几个
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(){
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());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
//unique去重,返回最后一位不重复的下一位,并把所有多余重复的元素排在这一位和这一位之后。然后再用erase将重复的真正清除掉
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;
}
#区间合并算法
----c++版
https://www.acwing.com/problem/content/805/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef pair<int,int> pll;
const int N=1e6+10;
int n;
vector<pll>segs;
void mergesegs(vector<pll>&segs){//核心操作
vector<pll>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;//更新当前区间
}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});
}
mergesegs(segs);
cout<<segs.size()<<endl;
return 0;
}