专栏文章
『数学笔记』提高组部分
算法·理论参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mior8x5b
- 此快照首次捕获于
- 2025/12/02 23:50 3 个月前
- 此快照最后确认于
- 2025/12/02 23:50 3 个月前
一些闲话
正文部分
因数
因数(Divisor),也称为约数,是指整数 除以整数 ()所得的商为整数且没有余数,此时称 为 的因数, 为 的倍数。
若某一个数 是 的因数,且 为质数,则称 为 的质因数。
若某一个数 是 的因数,且 为质数,则称 为 的质因数。
唯一分解定理:
每一个大于 的自然数都可以唯一分解为质数的乘积,且这种分解不考虑质数排列顺序时是唯一的。
也就是说,我们可以将大于 的自然数 写成以下形式:
也就是说,我们可以将大于 的自然数 写成以下形式:
其中, 为质因数个数, 为第 个质因数(一般来说从小到大), 为该质因数的次数。
实际上,一个大于 的自然数的各个因数就是由它的各个质因数组合及次方而来。
由乘法原理可得,我们可以把因数个数写成以下形式:
由乘法原理可得,我们可以把因数个数写成以下形式:
实际上 的因数是在 每一个的因数中分别挑一个相乘得来。
因数之和也就是各个质因数的各个次方相加后相乘。
因数之和也就是各个质因数的各个次方相加后相乘。
GCD 与 LCM
最大公约数(Greatest Common Divisor, GCD)是指两个或多个整数共有约数中最大的一个。
最小公倍数(Least Common Multiple, LCM)是指两个或多个整数共有倍数中最小的一个。
他们有如下性质:
最小公倍数(Least Common Multiple, LCM)是指两个或多个整数共有倍数中最小的一个。
他们有如下性质:
- 。
- 。
- 。
逆元与同余
- 同余:记 为 。
- 逆元:记满足 的一个解 为 模 的逆,记为 。
- 费马小定理:若 互质,则由 。
则 就是 模 的逆。 - 递推式:。
inv[1] = 1;
for(int i = 2;i <= n;++i) inv[i] = (p - p / i) * inv[p % i] % p;
欧拉函数与欧拉定理
定义欧拉函数 为不超过 且与 互质的正整数个数,为积性函数。
- 积性函数:若 且 ,则称 为积性函数。
欧拉函数有以下性质:
- 若 为质数,则 ,且 。
- ,其中 为 的因数数量, 为第 个因数(一般来说从小到大)。
代码:
CPPint phi(int p){
int ans = p;
for(int i = 2;i * i <= p;++i){
if(p % i == 0){
while(p % i == 0) p /= i;
ans /= i,ans *= (i-1);
}
}
if(p > 1) ans /= p,ans *= (p - 1);
return ans;
}
CPPvoid euler_sieve(){
for(int i = 0;i <= n;++i) phi[i] = i;
cnt = 0;
for(int i = 2;i <= n;++i){
if(phi[i] == i){//如果i是质数
primes[cnt++] = i;
phi[i] = i - 1;// 质数的欧拉函数值是自身减1
}
for(int j = 0;j < cnt && primes[j] * i <= n;++j){//遍历已找到的质数
if(i % primes[j] == 0){
// i能被primes[j]整除,说明primes[j]是i的最小质因子
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
else phi[i * primes[j]] = phi[i] * (primes[j] - 1);
// i不能被primes[j]整除,primes[j]是i*primes[j]的最小质因子
}
}
}
欧拉定理:
若 ,则 。
带入欧拉定理可得费马小定理。
带入欧拉定理可得费马小定理。
- 费马小定理:若 为质数,则 。
扩展欧拉定理:
可用于降幂,形式如下:
代码:
CPPph = phi(m);
ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9'){
x *= 10,x += (ch - '0');
if(x >= ph) x = x % ph,fl = 1;
ch = getchar();
}
if(fl == 1) x += ph;
cout << Fastpow(a,x,m) % m;
裴蜀定理
如果 均为整数,则有整数 使得 。
它有一堆推论或推广:
它有一堆推论或推广:
- 互质当且仅当存在整数 ,使得 。
- 一定存在整数 ,满足 。
- 一定存在整数 ,满足 。
威尔逊定理
若 为整数,则 可以整除 。
这个定理可以改写成以下形式:
这个定理可以改写成以下形式:
- 。
- 。
- ,且 为正整数。
- ,这也是 为质数的充要条件。
推论:
- 若 为质数,则 。
- 若 为大于 的合数,则 。
组合与排列
排列:。
组合:。
组合数有以下性质:
组合:。
组合数有以下性质:
- 。
- (帕斯卡公式)。
- 。
多重集的排列和组合:
- 无限多重集的排列:
是一个多重集,它有 个不同的元素,每个元素都有无穷重复个数, 的 排列个数为 。 - 有限多重集的排列:
是一个多重集,它有 个不同的元素,每个元素的重数分别为 , 的大小是 ,则 的 排列个数为 。 - 有限多重集的组合:
是一个多重集,它有 个不同的元素,每个元素都有无穷重复个数,那么 的 组合为 。
二项式系数:
二项式系数有两种计算方法:
- 递推:。
- 逆元:
。
卢卡斯定理:
对于质数 :
。
。
代码实现如下:
CPPvoid init(){
for(int i = 1;i <= 19491001;++i) f[i] = (f[i-1] * i) % MOD;
for(int i = 2;i <= 19491001;++i) r[i] = (MOD - MOD / i) * r[MOD % i] % MOD;
}
int C(int n,int k){//组合数 C(n, k)
if(k < 0 || k > n) return 0;
if(k == 0 || k == n) return 1;
if(k > n - k) k = n - k;
int q1 = f[n],q2 = (f[k] * f[n-k]) % MOD;
return q1 * r[q2] % MOD;
}
int lucas(int n,int k){//Lucas 定理计算 C(n, k) mod MOD
//C(n,m) % p = C(n/p,m/p) * C(n%p,m%p) % p
if(k < 0 || k > n) return 0;
if(k == 0) return 1;
int res = 1;
while(n || k){
int ni = n % MOD,ki = k % MOD;
if(ki > ni) return 0;
res = (res * C(ni, ki)) % MOD;
n /= MOD,k /= MOD;
}
return res;
}
容斥原理
集合的并等于集合的交的交错和(奇正偶负)。
集合的交等于全集的交减去补集的并。
集合的交等于全集的交减去补集的并。
Catalan 数
通项公式:
- 。
- 。
- 。
注意: 和 都有大数除法, 非常大,需要进行取模操作,直接做除法会损失精度,需要转换为逆元再取模。
圆排列:
是排列的一种,指 个数中选 个不同的元素排列成一个环形, 无头无尾。两个循环排列相同当且仅当所取元素的个数相同并且元素取法一致,在环上的排列顺序一致,记作 。
。
。
错位排列:
个有序的元素应有 个不同的排列,如若一个排列使得所有的元素不在原来的位置上,则称这个排列为错排。
。
。
。
。
不定方程与同余方程
二元线性丢番图方程(不定方程):
二元线性丢番图方程形如 。
有解的充分必要条件是 能整除 。
如果 是方程的一个特解,通解:
,。
其中 是任意整数。
求解一元线性同余方程等价于求解二元线性丢番图方程:
表示 是 的倍数,设为 倍,则有 。
这就是二元线性丢番图方程。
有解的充分必要条件是 能整除 。
如果 是方程的一个特解,通解:
,。
其中 是任意整数。
求解一元线性同余方程等价于求解二元线性丢番图方程:
表示 是 的倍数,设为 倍,则有 。
这就是二元线性丢番图方程。
扩展欧几里得算法:
是欧几里得算法的扩展,用于求解两个整数 的最大公约数,同时找到满足裴蜀等式 的整数解 和 。
具体过程如下:
具体过程如下:
- 递归过程:若 ,递归计算 ,并利用当前层的商 更新 和 的值。
- 下一层的解 和 满足 。
- 递归终止条件:当 时,此时 。
- 当前层的解 。
代码实现如下:
CPPint exgcd(int a,int b,int &x,int &y){
if(b == 0){
x = 1,y = 0;
return a;
}
int gcd = exgcd(b,a%b,y,x);
y -= a / b * x;
return gcd;
}
同余方程组-中国剩余定理
其中对于任意满足 且 的 ,保证 。
- 计算所有模数的积 。
。 - 计算第 个方程的 。
。 - 计算 。
- 。
int dickduck(int x,int y,int Mod){//龟速乘防止爆 long long
int ans = 0;
while(y >= 1){
if(y & 1) ans = (ans + x) % Mod;
y = y >> 1,x = (x << 1) % Mod;
}
return ans;
}
int exgcd(int a,int b,int &x,int &y){//扩展欧几里得算法
if(b == 0){
x = 1,y = 0;
return a;
}
int gcd1 = exgcd(b,a % b,y,x); //递归计算并交换 x,y
y -= a / b * x;
return gcd1;
}
int modinv(int a,int m){//模逆元(不能保证 m 是质数,不能用快速幂)
int x,y;
int gcd1 = exgcd(a,m,x,y);
if(gcd1 != 1) return -1;//无逆元
return (x % m + m) % m;
}
int cr(int n){//中国剩余定理
int M = 1,x = 0;
for(int i = 1;i <= n;++i) M *= mm[i]; //1.计算总模数 M
for(int i = 1;i <= n;++i){
int Mi = M / mm[i]; // Mi(其它模数之积)
int ti = modinv(Mi,mm[i]); // ti(Mi 在 mod mm[i] 下的逆元)
if (ti < 0) return -1; // 逆元不存在
x = (x + dickduck(aa[i],dickduck(Mi,ti,M),M)) % M; // 累加
}
return (x + M) % M;
}
同余方程组-扩展中国剩余定理
其中对于任意满足 且 的 ,不保证 。
对于模数不互质的情况,我们可以通过合并相邻两组方程的方式来逐步得到解。
。
转化得:。
所以:。
所以:。
现在, 都是已知的,只有 是未知的。我们不妨把它看成是关于 的不定方程。
那么根据裴蜀定理,,则原方程组无解。
由扩展欧几里得算法,两个方程可以等价合并为以下形式:
。
其中 。
代码:
CPP对于模数不互质的情况,我们可以通过合并相邻两组方程的方式来逐步得到解。
。
转化得:。
所以:。
所以:。
现在, 都是已知的,只有 是未知的。我们不妨把它看成是关于 的不定方程。
那么根据裴蜀定理,,则原方程组无解。
由扩展欧几里得算法,两个方程可以等价合并为以下形式:
。
其中 。
代码:
// 龟速乘(避免溢出):计算 (x * y) % Mod
int dickduck(int x,int y,int Mod){
int ans = 0;
while(y >= 1){
if(y & 1) ans = (ans + x) % Mod;
y = y >> 1,x = (x << 1) % Mod;
}
return ans;
}
// 扩展欧几里得算法:求解 ax + by = gcd(a, b)
int exgcd(int a,int b,int &x,int &y){
if(b == 0){
x = 1,y = 0;
return a;
}
int gcd1 = exgcd(b,a % b,y,x);
y -= a / b * x;
return gcd1;
}
// 扩展中国剩余定理(EXCRT)核心实现
int excr(int n){
int m1 = mm[1],r1 = aa[1];
r1 = (r1 % m1 + m1) % m1; //初始化解为第一个方程的最小非负整数
for (int i = 2;i <= n;++i){
int m2 = mm[i],r2 = aa[i],p,q;
r2 = (r2 % m2 + m2) % m2; //调整r2为模m2的最小非负整数
int d = exgcd(m1,m2,p,q); //求gcd(m1,m2)和系数p,q
if((r2 - r1) % d != 0) return -1; //检查解的存在性
int M = m2 / d; //计算调整后的模数
int t1 = ((r2 - r1) / d + M) % M,t2 = (p % M) + M;
int k0 = dickduck(t1,t2,M);
k0 = (k0 % M + M) % M; //调整为最小非负整数
int lcm = (m1 / d) * m2; //计算最小公倍数
r1 = (r1 + dickduck(m1,k0,lcm) + lcm) % lcm; //新解
r1 = (r1 % lcm + lcm) % lcm; //调整r1为最小非负
m1 = lcm; //更新模数为新的最小公倍数
}
return (r1 % m1 + m1) % m1; //返回最终解(最小非负整数)
}
感谢名单
- 感谢神犇 Hootime,是 TA 给我讲的裴蜀定理以及告诉了我很多 LaTeX 的公式。
- 感谢神犇 唐望(数竞生,所以没有 luogu 账号),是 TA 给我证明了裴蜀定理的推广形式。
- 感谢神犇 lijunxi2026,是 TA 借了我整理笔记的草稿纸。
- 感谢神犇 ligenC2026,是 TA 在我整理笔记时借了我修正带,成功避免了浪费草稿纸,以及在某些地方感谢我。
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...