目录
总
1.先举例子
2.再模拟实现
快速排序
分而治之
一个优美的思路:
左边一个指针i,右边一个指针j
保证指针 i 左边的值都比x要小
保证指针 j 右边的值都要比x大
然后分别往中间走,直到碰到 i 和 j 都不符合的时候
交换i和j所指代的数
然后接着走
直到 i 和 j 遇到为止
模板
int quick_sort(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]);
}
quick_sort(q,l,j);
quick_sort(q,j + 1,r);
}
归并排序
先递归
再合并
模板
void merge_sort(int q[],int l,int r)
{
if(l >= r) return;
int mid = l + r >> 1;
merge_sort(q,l,mid);
merge_sort(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 = l,j = 0;i <= r;i++,j++) q[i] = tmp[j];
}
二分
1.确定区间,确定目标在区间当中
2.找出一个性质,满足使得整个区间具有二段性
1.离散的情况
第一类
ans在右端点:M就归于右边mid-1,求mid的时候就+1
第一类模板
while(L < R)
{
M = (L + R + 1) / 2;
if M 是 绿
L = M; //根据这一步判断上一步需不需要 + 1 左边加一,右边不加
else
R = M - 1;
}
第二类
ans在左端点,M就归于左边
第二类模板
while(L < R)
{
M = (L + R) / 2; //右边不用+1
if M 是 蓝色
R = M;
else
L = M + 1;
}
前缀和
二维前缀和公式
求子矩阵的和
高精度加减乘除
存储
倒着存 倒着输出
去除首位0代码
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去掉前导0
模拟加法
代码
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e6 + 10;
//模拟加法
vector<int> add(vector<int> &A,vector<int> &B) //这里用 引用 & 不用再开一个数组占用空间
{
vector<int> C;
int t = 0; //t是中间值
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(t);
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;
}
模拟减法
代码
#include <iostream>
#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() - 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(); //去掉前导0
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 C = sub(B, A), cout << '-';
for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
cout << endl;
return 0;
}
模拟乘法
#include <iostream>
#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;
cin >> a >> b;
vector<int> A;
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<algorithm>
#include<vector>
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());
//去除首位的0 前面可能有很多0
while(C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
string a;
vector<int> A;
int B;
cin >> a >> B;
for(int i = a.size() - 1; i >= 0;i--) A.push_back(a[i] - '0');
int r = 0;
auto C = div(A,B,r);
for(int i = C.size() - 1;i >= 0;i--) cout << C[i];
cout << endl << r;
return 0;
}
求最小公倍数
辗转相除法(欧几里得算法)
int gcd(int a,int b)
{
return b ? gcd(b,a % b) : a;
}
扩展欧几里得算法
LL exgcd(LL a,LL b,LL &x,LL &y) //a b 已知 x y 未知 求a b 的最大公约数和x y d 最大公约数
{
if(!b) //b是0 的情况
{
x = 1,y = 0;
return a;
}
int d = exgcd(b,a % b,y,x);
y -= a / b * x;
return d;
}
辗转相减法
LL gcd_sub(LL a,LL b) //辗转相减法
{
if(a < b) swap(a,b);
if(b == 1) return a;
return gcd_sub(b,a / b);
}
算数基本定理
约数的个数和约数的和
线性筛法求素数
解决问题
以O(n)的时间复杂度求出n以内的所有的质数
代码
int primes[N],cnt; //存放所有的质数
bool st[N]; //当前的数有没有被筛选过
int get_peimes(int n)
{
for(int i = 2;i <= n;i++)
{
if(!st[i]) primes[cnt++] = i;
for(int j = 0;primes[j] * i <= n;j++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
贪心算法
无
双指针,BFS,图论
判断一个8位数是不是日期
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int months[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
//判断是不是日期
bool check(int date)
{
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if(!month || month > 13 || !day) return false;
if(month != 2 && day > months[month]) return false;
if(month == 2)
{
bool leap = year % 4 == 0 && year % 100 || year %400 == 0;
if(day > months[2] + leap) return false;
}
return true;
}
龟速乘法
LL qmul(LL a,LLb)
{
LL res = 0;
while(b)
{
if(b & 1)
res = res + a;
a = a + a;
b >> 1;
}
return res;
}
C++写取模所存在的问题以及解决的方案
//求 x 对 k 的取模的过程
( x % k + k) % k; //多一个 + k 的过程
快速幂算法模板
for(int k = n - 1;k;k >>= 1) //快速幂算法
{
if(k & 1) mul(f,f,a); //f = f * a
mul(a,a,a); //a = a * a
}
矩阵乘法模板
// C = A * B
void mul(int c[][N],int a[][N],int b[][N])
{
static int t[N][N]; //作为一个临时的数组
memset(t,0,sizeof t); //先清空
for(int i = 0;i < N;i++) //三次循环
for(int j = 0;j < N;j++)
for(int k = 0;k < N;k++)
t[i][j] = (t[i][j] + (LL)a[i][k] * b[k][j]);
memcpy(c,t,sizeof t);
}
输出 I64d 或者 lld
万能头文件
#include<bits/stdc++.h>