boolis_prime(int x){if(x <2)returnfalse;for(int i =2; i <= x / i; i ++)if(x % i ==0)returnfalse;returntrue;}
试除法分解质因数
#include<bits/stdc++.h>usingnamespace std;voidsolve(int x){if(x<1)return;if(x ==1|| x ==2){
cout << x <<" 1"<<endl;
cout << endl;return;}for(int i=2;i<=x/i;i++){if(x%i==0){int s =0;while(x%i ==0) x = x/i , s++;
cout << i <<" "<< s << endl;}}if(x >1)cout << x <<" 1"<< endl;
cout << endl;}intmain(){int n;
cin >> n;while(n--){int x;
cin >> x;solve(x);}}
朴素筛法求素数
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;}}
试除法求所有约数
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;}
#include<bits/stdc++.h>usingnamespace std;typedeflonglong LL;constint MOD =1e9+7;
unordered_map<int,int> primes;int n;intmain(){
cin >> n;while(n--){int x;
cin >> x;for(int i=2;i<=x/i;i++){while(x%i ==0){
x = x/i;
primes[i]++;}}if(x >1) primes[x]++;}
LL ans =1;for(auto prime : primes){
ans = ans *(prime.second +1)% MOD ;}
cout << ans << endl;}
一些数乘积的约数之和
#include<bits/stdc++.h>usingnamespace std;constint MOD =1e9+7;typedeflonglong LL;
unordered_map<int,int> primes;int n;intmain(){
cin >> n;while(n--){int x;
cin >> x;for(int i=2;i<=x/i;i++){while(x%i ==0){
primes[i]++;
x = x / i;}}if(x >1)primes[x]++;}
LL ans =1;for(auto prime : primes){int p = prime.first , a = prime.second;
LL res =1;while(a--) res =(res * p +1)% MOD ;
ans = ans * res % MOD;}
cout << ans%MOD << endl;}
欧拉函数
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;
ll ans ;intmain(){int n,x;
cin >> n;while(n--){
cin >>x;
ans = x;for(int i=2;i<=x/i;i++){if(x%i==0){while(x%i==0)x = x/i;
ans = ans / i *(i-1);}}if(x >1)ans = ans / x *(x-1);
cout << ans <<endl;}}
筛法求欧拉函数
#include<bits/stdc++.h>usingnamespace std;typedeflonglong ll;constint N =1100000;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);}}}intmain(){int n;
cin >> n;get_eulers(n);
ll ans =0;for(int i=1;i<=n;i++)ans += euler[i];
cout << ans << endl;}
快速幂
#include<bits/stdc++.h>usingnamespace std;typedeflonglong LL;intqpow(int a,int b,int mod){int ans =1;while(b){if(b&1) ans =(LL)ans * a % mod ;
a =(LL)a * a % mod;
b = b >>1;}return ans ;}intmain(){int a,b,mod;int t;
cin >>t ;while(t--){
cin >> a >> b >>mod;
cout <<qpow(a,b,mod)<< endl;}}
扩展欧几里得算法
// 求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;}
递归法求组合数
// 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;
通过预处理逆元的方式求组合数
//首先预处理出所有阶乘取模的余数fact[N],以及所有阶乘取模的逆元infact[N]//如果取模的数是质数,可以用费马小定理求逆元// 预处理阶乘的余数和阶乘逆元的余数
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;}// 例子#include<bits/stdc++.h>usingnamespace std;typedeflonglong LL;constint mod =1e9+7;constint N =110000;int fact[N],infact[N];intqpow(int a,int b,int p){int ans =1;while(b){if(b&1) ans =(LL)ans * a % p;
a =(LL)a * a % p;
b = b >>1;}return ans % p ;}intmain(){
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]*qpow(i,mod-2,mod)% mod ;}int t ;
cin >> t;while(t--){int a,b;
cin >> a >> b;
cout <<(LL)fact[a]* infact[b]% mod * infact[a-b]% mod << endl;}}
Lucas定理
若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;}
分解质因数法求组合数
当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用:
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]);
数论试除法判定质数试除法分解质因数朴素筛法求素数试除法求所有约数约数个数和约数之和一些数乘积的约数个数一些数乘积的约数之和欧拉函数筛法求欧拉函数快速幂扩展欧几里得算法递归法求组合数通过预处理逆元的方式求组合数Lucas定理分解质因数法求组合数试除法判定质数bool is_prime(int x){ if (x < 2) return false; for (int i = 2; i <= x / i; i ++ ) if (x % i == 0)