试除法
O ( n ) O(\sqrt{n}) O(n)
bool prime(int n)
{
if (n < 2) return 0;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return 0;
return 1;
}
Eratosthenes筛法
O ( n l o g l o g n ) O(n loglogn) O(nloglogn)
inline void primes(int n)
{
memset(v, 0, sizeof v);
for (int i = 2; i <= n; i++)
{
if (v[i]) continue;
prime[++cnt] = i;
for (int j = i; j <= n / i; j++)
v[i * j] = 1;
}
}
线性筛法
O ( n ) O(n) O(n)
inline void primes(int n)
{
memset(v, 0, sizeof v);
m = 0;
for (int i = 2; i <= n; i++)
{
if (v[i] == 0)
{
v[i] = i;
prime[++m] = i;
}
for (int j = 1; j <= m; j++)
{
if (prime[j] > v[i] || prime[j] > n / i) break;
v[i * prime[j]] = prime[j];
}
}
for (int i = 1; i <= m; i++
printf("%d ", prime[i]);
}
质因数分解
O ( n ) O(\sqrt{n}) O(n)
inline void divide(int n)
{
m = 0;
for (int i = 2; i * i <= n; i++)
{
if (n % i == 0)
{
p[++m] = i;
c[m] = 0;
while (n % i == 0)
{
n /= i;
c[m]++;
}
}
}
if (n > 1)
{
p[++m] = n;
c[m] = 1;
}
}
求 n 的正约数集合(试除法)
O ( n ) O(\sqrt{n}) O(n)
一个整数 n 的约数个数上界为 2 n 2\sqrt{n} 2n
inline void work(int n)
{
int factor[N], m = 0;
for (int i = 1; i * i <= n; i++)
{
if (n % i == 0)
{
factor[++m] = i;
if (i != n / i) factor[++m] = n / i;
}
}
}
求 1 ~ n 每个数的正约数合集(倍数法)
O ( n l o g n ) O(nlogn) O(nlogn)
1 ~ n 每个数的约数个数的总和大约为 n n n\sqrt{n} nn
inline void work(int n)
{
vector <int> factor[N];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n / i; j++)
factor[i * j].push_back(i);
}
最大公约数
更相减损术算法性能不稳定,最坏时间复杂度为 O ( m a x ( a , b ) ) O(max(a, b)) O(max(a,b))
辗转相除法近似为 O ( l o g ( a + b ) ) ) O(log(a + b))) O(log(a+b)))
//更相减损术
int gcd(int a, int b)
{
if(a == b) return a;
if(a > b) return gcd(a - b, b);
if(a < b) return gcd(a, b - a);
}
//辗转相除法(欧几里得算法)
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
欧拉函数
分解质因数法 O ( n ) O(\sqrt{n}) O(n)
Eratosthenes筛法 O ( n l o g n ) O(nlogn) O(nlogn)
线性筛法 O ( n ) O(n) O(n)
//分解质因数法(求 phi(n) )
int phi(int n)
{
int ans = n;
for (int i = 2; i * i <= n; i++)
if (n % i == 0)
{
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
//求 2 ~ n 中每个数的欧拉函数
//Eratosthenes筛法
void euler(int n)
{
for (int i = 2; i <= n; i++)
phi[i] = i;
for (int i = 2; i <= n; i++)
if (phi[i] == i)
{
for (int j = i; j <= n; j += i)
phi[j] = phi[j] / i * (i - 1);
}
}
//线性筛法
inline void euler(int n)
{
memset(v, 0, sizeof v); //最小质因子
m = 0; //质数数量
for (int i = 2; i <= n; i++)
{
if (v[i] == 0)
{
v[i] = i;
prime[++m] = i;
phi[i] = i - 1;
}
//给当前的 i 乘上一个因子
for (int j = 1; j <= m; j++)
{
// i 有比 prime[j] 更小的质因子,或者超出 n 的范围,停止循环
if (prime[j] > v[i] || prime[j] > n / i) break;
// prime[j] 是合数 i * prime[j] 的最小质因子
v[i * prime[j]] = prime[j];
phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]));
}
}
}
扩展欧几里得
O ( l o g n ) O(logn) O(logn)
求 a ∗ x ≡ 1 ( m o d a*x≡1(mod a∗x≡1(mod b ) b) b) 的最小整数解
设 a ∗ x + b ∗ y = 1 a * x + b * y = 1 a∗x+b∗y=1
inline int exgcd(int a, int b, iny &x, int &y)
{
if (!b)
{
x = 1;
y = 0;
return a;
}
int d = exgcd(a, b % a, x, y);
int z = x;
x = y;
y = z - y * (a / b);
return d;
}
inline void work()
{
scanf("%d%d", a, b);
exgcd(a, b, x, y);
printf("%d\n", (x % b + b) + b);
}
逆元
//快速幂法
ll Pow(ll x, ll y)
{
ll res = 1;
while (y)
{
if (y & 1) res = res * x % mod;
y /= 2;
x= x * x % mod;
}
return res;
}
inline ll inv(ll x)
{
return Pow(x, mod - 2);
}
//扩欧
inline int exgcd(int a, int b, iny &x, int &y)
{
if (!b)
{
x = 1;
y = 0;
return a;
}
int d = exgcd(a, b % a, x, y);
int z = x;
x = y;
y = z - y * (a / b);
return d;
}
inline ll inv(ll a)
{
ll x, y;
exgcd(a, mod, x, y);
return (x % mod + mod) % mod;
}
//线性
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = (p - p / i) * inv[p % i] % p;
中国剩余定理
O ( n l o g ( m o d ) ) O(nlog(mod)) O(nlog(mod))
求解同余方程组( m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn两两互质)
x
≡
a
1
(
m
o
d
x≡a_1(mod
x≡a1(mod
m
1
)
m_1)
m1)
x
≡
a
2
(
m
o
d
x≡a_2(mod
x≡a2(mod
m
2
)
m_2)
m2)
:
:
:
:
:
:
x
≡
a
n
(
m
o
d
x≡a_n(mod
x≡an(mod
m
n
)
m_n)
mn)
m m = ∏ i = 1 n m i mm = ∏_{i = 1}^{n}m_i mm=∏i=1nmi
m i = m m / m i mi = mm / m_i mi=mm/mi
t i t_i ti 为线性同余方程 m i ⋅ t i ≡ 1 ( m o d mi·t_i≡1(mod mi⋅ti≡1(mod m i ) m_i) mi) 的一个解
方程组的解为 x = ∑ i = 1 n a i m i t i x = \sum_{i = 1}^{n} a_imit_i x=∑i=1naimiti
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (!b)
{
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll z = x;
x = y;
y = z - y * (a / b);
return d;
}
inline void work()
{
sc(n);
mm = 1;
for (int i = 1; i <= n; i++)
{
sc(m[i]);
sc(a[i]);
mm *= m[i];
}
for (int i = 1; i <= n; i++)
{
ll mi = mm / m[i];
ll x, y;
ll d = exgcd(mi, m[i], x, y);
ans = (ans + mi * x * a[i]) % mm;
}
printf("%lld\n", (ans + mm) % mm);
}
扩展中国剩余定理(不互质)
O ( n l o g n ) O(nlogn) O(nlogn)
m m = l c m ( m 1 , m 2 , . . . , m k − 1 ) mm = lcm(m_1, m_2,...,m_{k-1}) mm=lcm(m1,m2,...,mk−1)
x + i ∗ m m x+i*mm x+i∗mm是前 k − 1 k-1 k−1个方程的通解
x + t ∗ m m ≡ a k ( m o d x+t*mm≡a_k(mod x+t∗mm≡ak(mod m k ) m_k) mk)
等价于 m m ∗ t ≡ a k − x ( m o d mm*t≡a_k-x(mod mm∗t≡ak−x(mod m k ) m_k) mk)
则前 k k k 个方程的一个解为 x + t ∗ m x + t*m x+t∗m
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (!b)
{
x = 1;
y = 0;
return a;
}
ll d = exgcd(b, a % b, x, y);
ll z = x;
x = y;
y = z - y * (a / b);
return d;
}
ll CRT()
{
ll mm = m[1];
ll x = a[1], y;
for (int i = 2; i <= n; i++)
{
a[i] -= x;
ll xx = x;
x = 0;
y = 0;
ll d = exgcd(mm, m[i], x, y);
if (a[i] % d) return -1;
x *= a[i] / d;
ll c = m[i] / d;
x = (x % c + c) % c;
x = xx + x * mm;
mm = mm * m[i] / d;
x = (x + mm) % mm;
}
return x;
}
Baby Step,Giant Step(大步小步)
O ( p ) O(\sqrt{p}) O(p)
求解高次同余方程
a x ≡ b ( m o d a^x≡b(mod ax≡b(mod p ) p) p)
inline ll Pow(ll x, ll y)
{
ll res = 1;
while (y)
{
if (y & 1) res = res * x % p;
y >>= 1;
x = x * x % p;
}
return res;
}
int BSGS(int a, int b)
{
map <int, int> hash;
hash.clear();
b %= p;
int t = (int)sqrt(p) + 1;
for (int j = 0; j < t; j++)
{
int val = (long long)b * Pow(a, j) % p;
hash[val] = j;
}
a = Pow(a, t);
if (a == 0) return b == 0 ? 1 : -1;
for (int i = 0; i <= t; i++)
{
int val = Pow(a, i);
int j = hash.find(val) == hash.end() ? -1 : hash[val];
if (j >= 0 && i * t - j >= 0) return i * t - j;
}
return -1;
}
矩阵乘法
O ( l o g n ) O(logn) O(logn) n n n 为指数
//斐波那契数列
int k;
struct Xiao
{
int sum[2][2];
Xiao()
{
sum[0][0] = sum[0][1] = sum[1][0] = 1;
sum[1][1] = 0;
}
};
Xiao mul(Xiao x, Xiao y)
{
Xiao a;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
{
a.sum[i][j] = 0;
for (int k = 0; k < 2; k++)
a.sum[i][j] += x.sum[i][k] * y.sum[k][j];
a.sum[i][j] %= 10000;
}
return a;
}
Xiao Pow(int x)
{
Xiao a, b;
a.sum[1][0] = a.sum[0][1] = 0;
a.sum[1][1] = 1;
while (x)
{
if (x % 2) a = mul(a, b);
x /= 2;
b = mul(b, b);
}
return a;
}
inline void work()
{
while (sc(k) && k != -1)
{
Xiao ans = Pow(k);
printf("%d\n", ans.sum[1][0]);
}
}
高斯消元
O ( n 3 ) O(n^3) O(n3)
球形空间产生器
inline void work()
{
sc(n);
for (int i = 1; i <= n + 1; i++)
{
for (int j = 1; j <= n; j++)
scanf("%lf", &a[i][j]);
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
c[i][j] = 2 * (a[i][j] - a[i + 1][j]); //系数矩阵
b[i] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j]; //常数
}
//高斯消元
for (int i = 1; i <= n; i++)
{
for (int j = i; j <= n; j++) //找到 x[i] 的系数不为 0 的一个方程
{
if (fabs(c[j][i]) > 1e-8)
{
for (int k = 1; k <= n; k++)
swap(c[i][k], c[j][k]);
swap(b[i], b[j]);
}
}
for (int j = 1; j <= n; j++) //消去其他方程的 x[i] 的系数
{
if (i == j) continue;
double rate = c[j][i] / c[i][i];
for (int k = i; k <= n; k++)
c[j][k] -= c[i][k] * rate;
b[j] -= b[i] * rate;
}
}
for (int i = 1; i < n; i++)
printf("%.3lf ", b[i] / c[i][i]);
printf("%.3lf\n", b[n] / c[n][n]);
}