专栏文章

数学知识

算法·理论参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minlowky
此快照首次捕获于
2025/12/02 04:27
3 个月前
此快照最后确认于
2025/12/02 04:27
3 个月前
查看原文

gcd 与 lcm

几个重要的公式:
gcd(a,b)=gcd(a,a+b)=gcd(b,amodb)\gcd(a,b)=\gcd(a,a+b)=\gcd(b,a\mod b)
gcd(k×a,k×b)=k×gcd(a,b)\gcd(k\times a,k\times b)=k\times\gcd(a,b)
gcd(a,b,c)=gcd(gcd(a,b),c)\gcd(a,b,c)=\gcd(\gcd(a,b),c)
gcd(a,b)=d,则gcd(a/d,b/d)=1,互素若\gcd(a,b)=d,则\gcd(a/d,b/d)=1,互素

算数基本定理

任何一个大于1的自然数N,如果N不是质数,那么N可以唯一分解成有限个质数的乘积:n=p1c1p2c2...pmcmn=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}},其中 p 为素数。

由此,设 a=p1c1p2c2...pmcm,b=p1f1p2f2...pmfma=p_{1}^{c_{1}}p_{2}^{c_{2}}...p_{m}^{c_{m}},b=p_{1}^{f_{1}}p_{2}^{f_{2}}...p_{m}^{f_{m}}
gcd(a,b)=p1min(c1,f1)p2min(c2,f2)...pmmin(cm,fm)\gcd(a,b)=p_{1}^{\min(c_{1},f_{1})}p_{2}^{\min(c_{2},f_{2})}...p_{m}^{\min(c_{m},f_{m})}
lcm(a,b)=p1max(c1,f1)p2max(c2,f2)...pmmax(cm,fm)lcm(a,b)=p_{1}^{\max(c_{1},f_{1})}p_{2}^{\max(c_{2},f_{2})}...p_{m}^{\max(c_{m},f_{m})}

所以 lcm(a,b)=a×b/gcd(a,b)lcm(a,b)=a\times b/\gcd(a,b)

例题

给定 L,GL,G,问满足 gcd(x,y,z)=Ggcd(x,y,z)=Glcm(x,y,z)=Llcm(x,y,z)=Lx,y,zx,y,z 有多少个。
注意问题变形为满足 gcd(x/G,y/G,z/G)=1,lcm(x/G,y/G,z/G)=L/G\gcd(x/G,y/G,z/G)=1,lcm(x/G,y/G,z/G)=L/G(x/G),(y/G),(z/G)(x/G),(y/G),(z/G) 有多少个。
由算术基本定理,令
(x/G)=p1i1,p2i2,p3i3(x/G) = p_{1}^{i_{1}},p_{2}^{i_{2}},p_{3}^{i_{3}},
(y/G)=p1j1,p2j2,p3j3(y/G)=p_{1}^{j_{1}},p_{2}^{j_{2}},p_{3}^{j_{3}},
(z/G)=p1k1,p2k2,p3k3(z/G)=p_{1}^{k_{1}},p_{2}^{k_{2}},p_{3}^{k_{3}},
(L/G)=p1t1,p2t2,p3t3(L/G)=p_{1}^{t_{1}},p_{2}^{t_{2}},p_{3}^{t_{3}}
根据 gcd\gcd 与指数的关系,我们可以知道要使式子成立,则 min(i1,j1,k1)=0\min({i_{1},j_{1},k_{1}})=0 满足互素性质,接下来分类讨论取值满足 max(i1,j1,k1)=t1\max({i_{1},j_{1},k_{1}})=t_{1},实际需要分解 G/LG/L 的质因数。

裴蜀定理

若 a,b 为正整数,则有 x,y 使 ax+by=gcd(a,b)

推论:a 与 b 互素当且仅当 ax + by=1,也就是gca(a,b)=1

线性丢番图方程

也叫一元二次不定方程形如 ax+by=cax+by=ca,ba,b 为常数,x,yx,y 为变量。

定理:设 d = gcd(a,b),若d 不能整除 c,方程无解;否则方程有特解 (x0,y0)(x_{0},y_{0}),通解 x=x0+(b/d)n,y=y0(a/d)nx=x_{0}+(b/d)n,y=y_{0}-(a/d)n

如何求?

扩展欧几里得算法

先用扩展欧几里得求出 ax+by=gcd(a,b)ax+by=\gcd(a,b) 的特解 (x0,y0)(x_{0},y_{0}),令此式左右同乘 (c/gcd(a,b))(c/gcd(a,b)) 变为 ax0c/gcd(a,b)+by0c/gcd(a,b)=cax_{0}c/gcd(a,b)+by_{0}c/gcd(a,b)=c,所以 ax+by=cax+by=c 的特解就是 x=x0cgcd(a,b),y=y0cgcd(a,b)x^{'}=x_{0}c\gcd(a,b),y^{'}=y_{0}c\gcd(a,b)
CPP
int exgcd(int a,int b,int &x,int &y){
	if(!b){
		x=1,y=0;
		return a;
	}
	d = exgcd(b,a%b,y,x);
	y -= a/b * x;
	return d;
}

同余

一元线性同余方程

逆元

对于非零整数 a,ma,m,如果存在 bb 使得 ab1(modm)ab\equiv 1\pmod m,就称 𝑏𝑏aa 在模 mm 意义下的逆元。
这相当于说,bb 是线性同余方程 ax1(modm)ax\equiv 1\pmod m 的解。根据 线性同余方程 的性质可知,当且仅当 gcd(a,m)=1\gcd(a,m)=1,即 a,ma,m 互素时,逆元 a1modma^{-1}\bmod m 存在,且在模 mm 的意义下是唯一的。
求解逆元的多种形式:

单个逆

exgcdexgcd:要求 gcd(a,m)=1\gcd(a,m)=1
CPP
void ex_gcd(int a, int b, int& x, int& y) {
  if (!b) {
    x = 1;
    y = 0;
  } else {
    ex_gcd(b, a % b, y, x);
    y -= a / b * x;
  }
}
快速幂:要求 mm 为素数
根据费马小定理 aam2=am11(modm)a*a^{m-2}=a^{m-1}\equiv 1\pmod m 以及逆元的唯一性可知,逆元 a1modpa^{-1}\bmod p 就等于 ap2modpa^{p-2}\bmod p,因此可以直接使用 快速幂 在 O(logp)O(\log p) 时间内计算:
CPP
int qpow(int a, int b, int m) {
  long long res = 1, po = a;
  for (; b; b >>= 1) {
    if (b & 1) res = res * po % m;
    po = po * po % m;
  }
  return res;
}

int inverse(int a, int p) { return qpow(a, p - 2, p); }

多个逆

线性递推求逆:

同余方程组

𝑥 ≡𝑎1(mod𝑛1)
𝑥 ≡𝑎2(mod𝑛2)
𝑥 ≡𝑎𝑘(mod𝑛𝑘)
求同余方程组的解

中国剩余定理 CRT

此方法只适用于模数互质的情况,步骤:
  1. 计算总模数 MM = 各个模数之积
  2. 计算 mi=Mnim_{i}=\frac{M}{n_{i}}
  3. exgcdexgcd计算 mim_{i} 的逆元
  4. 方程在模 MM 意义下的唯一解:x=i=1nai×mi×mi1(modM)x=\sum_{i=1}^{n}a_{i}\times m_{i}\times m_{i}^{-1}(mod M)
CPP
for(int i=1;i<=n;i++){
		read(a[i]); read(b[i]);
		M = M * a[i];//模数的乘积 
	}
	for(int i=1;i<=n;i++){
		__int128 m = M / a[i],x,y;//模数积除以各自的模数 
		exgcd(m,a[i],x,y);//exgcd计算m的逆元 
		ans = (ans + b[i] * m * x % M) % M;//m * m^-1 * 权值 取模总模数 
	}

整除分块

有这样一个问题:
以 n=10 为例
i12345678910
ni\lfloor\frac{n}{i}\rfloor10532211111
注意到 ni\lfloor\frac{n}{i}\rfloor 的值有重复连续的区间,这启示我们按 ni\lfloor\frac{n}{i}\rfloor 的值 分块。
接下来证明分块少于 2n2\sqrt n 种。
i<=ni <= \sqrt n 时,ni\lfloor\frac{n}{i}\rfloor 的值大于等于 n\sqrt n,共 n\sqrt n 个;当 i>ni > \sqrt n 时,ni<n\lfloor\frac{n}{i}\rfloor < \sqrt n,也有 n\sqrt n 个。
当一个区间内的值为 kk 时,区间右端点为 xk\lfloor\frac{x}{k}\rfloor,证明略。
CPP
ll get(ll x){
	ll res = 0;
	for(ll i=1,j;i<=x;i=j+1){
		j = x / (x / i);
		res += (x/i) * (j - i + 1);
	}
	return res;
}
以 n=10 为例
i12345678910
ni\lfloor\frac{n}{i}\rfloor10532211111
i×nii\times \lfloor \frac{n}{i} \rfloor 101091210678910
相当于每个区间是一个首项为 xi×i\lfloor\frac{x}{i}\rfloor\times i,尾项为 xi×xk\lfloor\frac{x}{i}\rfloor\times\lfloor\frac{x}{k}\rfloor,长度为(rl+1)(r - l + 1) ,公差为 ni\lfloor\frac{n}{i}\rfloor 的等差数列。
CPP
ll get(ll x){
	ll res = 0;
	for(ll i=1,j;i<=x;i=j+1){
		ll k = x / i;
		j = x / k;
		res += k * (i + j) * (j - i + 1) / 2; 
	}
	return res;
}
模拟赛遇到了,没做出来。 给定 a,ba,b 两个序列,定义 ci=j=1iaij×bimodjc_{i} = \sum_{j=1}^{i} a_{\lfloor\frac{i}{j}\rfloor} \times b_{i\mod j},求序列 cc
和上面的结论一样,根据整除分块,ni\lfloor\frac{n}{i}\rfloor 相同的 aa 是连续的一段,且只有 sqrtnsqrt_{n} 级别,注意到 imodji \mod j 在这相同的一段中是公差为 ni\lfloor\frac{n}{i}\rfloor 的等差数列的形式,所以说我们就可以利用根号分治的思想,小于根号 k 的暴力计算,大于根号 k 的进行下标的等差数列前缀和预处理,利用整除分块快速计算。
-2025.11.18

评论

0 条评论,欢迎与作者交流。

正在加载评论...