算法
输入输出加速:
cin/cout/scanf/printf:
cin.tie(0);
ios::sync_with_stdio(false);
基础算法:
排序:
//快排模板
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N];
void quick(int q[], int l, int r){
if(l >= r){
return;
}
//x是取得比较位,i,左边界,j,右边界
int x = q[(l + r) / 2], 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(q, l, j);
quick(q, j + 1, r);
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d",&q[i]);
}
quick(q, 0, n - 1);
for(int i = 0; i < n; i++){
cout << q[i] << " ";
}
return 0;
}
//归并排序
位运算:
数学知识:
数论:
质数
(数论) O(1)
结论:
如果 a,b 均是正整数且互质,那么由 ax+by,x≥0,y≥0 不能凑出的最大数是 ab−a−b
下面给出证明:
首先证明 ab−a−b不能被 ax+bx,x≥0,y≥0表示出。
反正法,假设 ab−a−b=ax+by,那么 ab=a(x+1)+b(y+1),由于 a|ab,a|a(x+1),所以 a|b(y+1),由于 a,ba,b 互质,所以 a|(y+1),由于 y≥0,所以 a<=y+1,所以 b(y+1)≥ab。同理可得 a(x+1)≥ab,所以 a(x+1)+b(y+1)≥2ab>ab,矛盾。
证明 ab−a−b+d,d>0 一定可以表示成 ax+by,x,y≥0的形式。
质数的定义: 是针对大于1的自然数,小于等于1的既不是质数也不是合数。
在大于1的整数中,如果只包含本身这两个约数,就被称作质数或素数。
暴力解法(试除法)
//判定一个数是否为质数
bool isPrime(a) {
if (a < 2) return 0;
for (int i = 2; i < a; ++i)
if (a % i == 0) return 0;
return 1;
}
//时间复杂度为O(N)
//判定一个数是否为质数
n可以整除 d, n同样可以整除 n/d;
//约数都是成对出现的,所以我们可以枚举较小的数
//即 d <= n/d,可以写成d <= sqrt(n);
//由于sqrt() 运算速度慢, d * d <= n,在(d + 1) * (d + 1) <= n时,
//会存在溢出风险,使得d^2为负值,故不尝试
bool isPrime(a) {
if (a < 2) return 0;
for (int i = 2; i < a / i; ++i)
if (a % i == 0) return 0;
return 1;
}
//时间复杂度为O(sqrt(N))
分解质因数(试除法)
例:给定n个正整数ai,将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。
//从小到大枚举所有数,
void divide(int n){
for(int i = 2; i < n; i++){
if(n % i == 0){
int s = 0;
while(n % i){
n /= i;
s++;
}
cout << i << s;
}
}
if(n > 1) cout << n << 1;
}
例:筛质数
给定一个正整数n,请你求出1~n中质数的个数。
const int N = 1000010;
bool st[N];
int primes[N];
int cnt;
void get_primes(int n){
for(int i = 2; i <= n; i++){
if(!st[i]) primes[cnt ++ ] = i;
for(int j = 0; primes[j] <= n / i; j++){
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
埃拉托斯特尼筛法
const int N = 1000010;
bool is_prime[N];
int prime[N];
int p;
int Eratosthenes(int n) {
int p = 0;
for (int i = 0; i <= n; ++i) is_prime[i] = 1;
//is_prime 设置为0则不是质数
is_prime[0] = is_prime[1] = 0;
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
prime[p++] = i; // prime[p]是i,后置自增运算代表当前素数数量
for (int j = i + i; j <= n; j += i) // 因为从 2 到 i - 1 的倍数我们之前筛过了
is_prime[j] = 0;
// 这里直接从 i的倍数开始,提高了运行速度
// 是i的倍数的均不是素数
}
}
return p;
}
}
线性筛法
n只会被最小质因子筛掉。
分为两种情况:
1. i % pj == 0:
pj一定是i的最小质因子,pj一定是pj * i 的最小质因子。
2. i % pj != 0;
pj一定小于i的所有质因子,pj一定时pj * i 的最小质因子。
for(int i = 2; i < =n; i++){
if(!st[i]) primes[cnt++] = i;
for(int j = 0; primes[j] <= n/i; j++){
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
最大公约数/最小公倍数
最大公约数
/*
a mod b = a - (a / b) * b;
= a - c * b;
a / d, b / d, ax + by / d;
(a, b) = (b, a % b)
*/
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
最小公倍数
a * b / gcd(a, b);
试除法求约数:
给定n个正整数ai,对于每个整数ai,请你按照从小到大的顺序输出它的所有约数。
vector<int> get_divisors(int n){
vector<int> res;
for(int i = 1; i <= n / i; i++){
if(n % i == 0){
res.push_back(i);
if(i != n / i) res.push_back(n / i);//
}
}
sort(res.begin(), res.end())