boolis_prime(int x){if(x <2)returnfalse;for(int i =2; i <= x / i; i ++)if(x % i ==0)returnfalse;returntrue;}
试除法分解质因数 —— 模板题 AcWing 867. 分解质因数
voiddivide(int x){for(int i =2; i <= x / i; i ++)if(x % i ==0){int s =0;while(x % i ==0) x /= i, s ++;
cout << i <<' '<< s << endl;}if(x >1) cout << x <<' '<<1<< endl;
cout << endl;}
朴素筛法求素数 —— 模板题 AcWing 868. 筛质数
int primes[N], cnt;// primes[]存储所有素数bool st[N];// st[x]存储x是否被筛掉voidget_primes(int n){for(int i =2; i <= n; i ++){if(st[i])continue;
primes[cnt ++]= i;for(int j = i + i; j <= n; j += i)
st[j]=true;}}
线性筛法求素数 —— 模板题 AcWing 868. 筛质数
int primes[N], cnt;// primes[]存储所有素数bool st[N];// st[x]存储x是否被筛掉voidget_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;}}}
试除法求所有约数 —— 模板题 AcWing 869. 试除法求约数
vector<int>get_divisors(int x){
vector<int> res;for(int i =1; i <= x / i; i ++)if(x % i ==0){
res.push_back(i);if(i != x / i) res.push_back(x / i);}sort(res.begin(), res.end());return res;}
intphi(int x){int res = x;for(int i =2; i <= x / i; i ++)if(x % i ==0){
res = res / i *(i -1);while(x % i ==0) x /= i;}if(x >1) res = res / x *(x -1);return res;}
筛法求欧拉函数 —— 模板题 AcWing 874. 筛法求欧拉函数
int primes[N], cnt;// primes[]存储所有素数int euler[N];// 存储每个数的欧拉函数bool st[N];// st[x]存储x是否被筛掉voidget_eulers(int n){
euler[1]=1;for(int i =2; i <= n; i ++){if(!st[i]){
primes[cnt ++]= i;
euler[i]= i -1;}for(int j =0; primes[j]<= n / i; j ++){int t = primes[j]* i;
st[t]=true;if(i % primes[j]==0){
euler[t]= euler[i]* primes[j];break;}
euler[t]= euler[i]*(primes[j]-1);}}}
快速幂 —— 模板题 AcWing 875. 快速幂
求 m^k mod p,时间复杂度 O(logk)。
intqmi(int m,int k,int p){int res =1% p, t = m;while(k){if(k&1) res = res * t % p;
t = t * t % p;
k >>=1;}return res;}
扩展欧几里得算法 —— 模板题 AcWing 877. 扩展欧几里得算法
// 求x, y,使得ax + by = gcd(a, b)intexgcd(int a,int b,int&x,int&y){if(!b){
x =1; y =0;return a;}int d =exgcd(b, a % b, y, x);
y -=(a/b)* x;return d;}
高斯消元 —— 模板题 AcWing 883. 高斯消元解线性方程组
// a[N][N]是增广矩阵intgauss(){int c, r;for(c =0, r =0; c < n; c ++){int t = r;for(int i = r; i < n; i ++)// 找到绝对值最大的行if(fabs(a[i][c])>fabs(a[t][c]))
t = i;if(fabs(a[t][c])< eps)continue;for(int i = c; i <= n; i ++)swap(a[t][i], a[r][i]);// 将绝对值最大的行换到最顶端for(int i = n; i >= c; i --) a[r][i]/= a[r][c];// 将当前行的首位变成1for(int i = r +1; i < n; i ++)// 用当前行将下面所有的列消成0if(fabs(a[i][c])> eps)for(int j = n; j >= c; j --)
a[i][j]-= a[r][j]* a[i][c];
r ++;}if(r < n){for(int i = r; i < n; i ++)if(fabs(a[i][n])> eps)return2;// 无解return1;// 有无穷多组解}for(int i = n -1; i >=0; i --)for(int j = i +1; j < n; j ++)
a[i][n]-= a[i][j]* a[j][n];return0;// 有唯一解}
递归法求组合数 —— 模板题 AcWing 885. 求组合数 I
// c[a][b] 表示从a个苹果中选b个的方案数for(int i =0; i < N; i ++)for(int j =0; j <= i; j ++)if(!j) c[i][j]=1;else c[i][j]=(c[i -1][j]+ c[i -1][j -1])% mod;
通过预处理逆元的方式求组合数 —— 模板题 AcWing 886. 求组合数 II
首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N]
如果取模的数是质数,可以用费马小定理求逆元
intqmi(int a,int k,int p)// 快速幂模板{int res =1;while(k){if(k &1) res =(LL)res * a % p;
a =(LL)a * a % p;
k >>=1;}return res;}// 预处理阶乘的余数和阶乘逆元的余数
fact[0]= infact[0]=1;for(int i =1; i < N; i ++){
fact[i]=(LL)fact[i -1]* i % mod;
infact[i]=(LL)infact[i -1]*qmi(i, mod -2, mod)% mod;}
Lucas定理 —— 模板题 AcWing 887. 求组合数 III
若p是质数,则对于任意整数 1<= m <= n,有:
C(n, m)=C(n % p, m % p)*C(n / p, m / p)(mod p)intqmi(int a,int k,int p)// 快速幂模板{int res =1% p;while(k){if(k &1) res =(LL)res * a % p;
a =(LL)a * a % p;
k >>=1;}return res;}intC(int a,int b,int p)// 通过定理求组合数C(a, b){if(a < b)return0;
LL x =1, y =1;// x是分子,y是分母for(int i = a, j =1; j <= b; i --, j ++){
x =(LL)x * i % p;
y =(LL) y * j % p;}return x *(LL)qmi(y, p -2, p)% p;}intlucas(LL a, LL b,int p){if(a < p && b < p)returnC(a, b, p);return(LL)C(a % p, b % p, p)*lucas(a / p, b / p, p)% p;}
分解质因数法求组合数 —— 模板题 AcWing 888. 求组合数 IV
当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用:
1. 筛法求出范围内的所有质数
2. 通过 C(a, b)= a!/ b!/(a - b)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2+ n / p^3+...3. 用高精度乘法将所有质因子相乘
int primes[N], cnt;// 存储所有质数int sum[N];// 存储每个质数的次数bool st[N];// 存储每个数是否已被筛掉voidget_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;}}}intget(int n,int p)// 求n!中的次数{int res =0;while(n){
res += n / p;
n /= p;}return res;}
vector<int>mul(vector<int> a,int b)// 高精度乘低精度模板{
vector<int> c;int t =0;for(int i =0; i < a.size(); i ++){
t += a[i]* b;
c.push_back(t %10);
t /=10;}while(t){
c.push_back(t %10);
t /=10;}return c;}get_primes(a);// 预处理范围内的所有质数for(int i =0; i < cnt; i ++)// 求每个质因数的次数{int p = primes[i];
sum[i]=get(a, p)-get(b, p)-get(a - b, p);}
vector<int> res;
res.push_back(1);for(int i =0; i < cnt; i ++)// 用高精度乘法将所有质因子相乘for(int j =0; j < sum[i]; j ++)
res =mul(res, primes[i]);