Ⅰ GCD
(1) 概念
gcd是指最大公约数(Greatest Common Divisor)(18能被2整除,18是2的倍数,2是18的约数)记作(a,b)
几何概念
一个24×60的长方形区域最多可以被分成多个完整的12×12的正方形,所以12是(24,60)的gcd
(2) 求法
质数分解法
48 = 2 × 2 × 2 × 2 × 3
180 = 2 × 2 × 3 × 3 × 5
辗转相除法(欧几里得算法)
内容
求(62,36 )
62 / 36 = 1 (余26) —— (36,26)
36 / 26 = 1 (余 10) —— (26,10)
26 / 10 = 2 (余6) —— (10,6)
10 / 6 = 1 (余4) —— (6,4)
6 / 4 = 1 (余2) —— (4,2)
得到的结果:能放下多少个正方形
余数:剩下的区域能最大能放正方形的尺寸
几何概念
每次取能放下最大正方形的区域
代码
//递归写法
int gcd(int a,int b)
{
if(a%b==0)
return b;
return gcd(b,a%b);
}
//循环写法
int gcd(int a,int b)
{
int temp;
while(b)
{
temp = b;
b = a % b;
a = temp;
}
return a;
}
(3) 性质
- 满足交换律: g c d ( a , b ) = g c d ( b , a ) gcd(a,b) = gcd(b,a) gcd(a,b)=gcd(b,a)
- 满足分配律: g c d ( m a , m b ) = m ∗ g c d ( a , b ) gcd(ma,mb) = m *gcd(a,b) gcd(ma,mb)=m∗gcd(a,b)
- 在乘法函数中: g c d ( a b , m ) = g c d ( a , m ) ∗ g c d ( b , m ) gcd(ab,m) = gcd(a,m) * gcd(b,m) gcd(ab,m)=gcd(a,m)∗gcd(b,m)
- 和最小公倍数(lcm)的关系: g c d ( a , b ) ∗ l c m ( a , b ) = a b gcd(a, b) * lcm(a, b) = ab gcd(a,b)∗lcm(a,b)=ab
- 在坐标里,将点(0, 0)和(a, b)连起来,通过整数坐标的点的数目(除了(0, 0)一点之外)就是gcd(a, b)
- 两个整数的最大公因子和最小公倍数中存在分配律:
- g c d ( a , l c m ( b , c ) ) = l c m ( g c d ( a , b ) , g c d ( a , c ) ) gcd(a, lcm(b, c)) = lcm(gcd(a, b), gcd(a, c)) gcd(a,lcm(b,c))=lcm(gcd(a,b),gcd(a,c))
- l c m ( a , g c d ( b , c ) ) = g c d ( l c m ( a , b ) , l c m ( a , c ) ) lcm(a, gcd(b, c)) = gcd(lcm(a, b), lcm(a, c)) lcm(a,gcd(b,c))=gcd(lcm(a,b),lcm(a,c))
- *扩展欧几里得算法(见后文)
- m是任意整数,则有 g c d ( a + m ⋅ b , b ) = g c d ( a , b ) gcd(a + m⋅b, b) = gcd(a, b) gcd(a+m⋅b,b)=gcd(a,b)
(4) 相关题目
① 求1-n范围内,不同的数对中,gcd的最大值
② (a,b) + [a,b] = x
③ *Orac and LCM,待改进
④ 蒜头君的数轴,两次gcd
Ⅱ LCM
LCM是指最小公倍数(Least Common Multiple)记作[a,b]
求法
( a , b ) × [ a , b ] = a × b
即:两个数的乘积等于这两个数的最大公约数与最小公倍数的积
应用
分数的加减法
中国剩余定理(正确的题在最小公倍数内有解,有唯一的解)
从集合的角度理解:并集和交集
Ⅲ 算数基本定理
内容
任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积N = P1a1P2a2P3a3…Pnan。这里P1<P2<P3…<Pn均为质数,其中指数ai是正整数。这样的分解称为 N 的标准分解式。
▶ 又叫唯一分解定理
▶ 把对自然数的研究转化为对素数的研究
▶ 存在性 & 唯一性
Ⅳ 分解质因数
就是把一个合数用质因数相乘的形式表示出来,如:30 = 2 × 3 × 5
▶ 可用反证法证明不存在最大的质数
代码
for (int i = 2; i*i <= n; i++)
{
while (n%i == 0)
{
n = n / i;
cout << i;
if (n != 1)cout << "*";
}
}
Ⅴ 欧拉函数
背景
内容
在≤x的正整数中,与x互质的数的数目。例如φ(8)=4,因为1,3,5,7均和8互质
(其中p1, p2……pn为x的所有质因数,x是不为0的整数,φ(1)=1)
性质
① 若n是质数p的k次幂,则有:
----因为除了p的倍数外,其他数都跟n互质。
② 欧拉函数是积性函数:若m,n互质,则有
例如:
φ
(
72
)
=
φ
(
2
3
×
3
2
)
=
2
3
−
1
(
2
−
1
)
×
3
2
−
1
(
3
−
1
)
=
2
2
×
1
×
3
×
2
=
24
{\displaystyle \varphi (72)=\varphi (2^{3}\times 3^{2})=2^{3-1}(2-1)\times 3^{2-1}(3-1)=2^{2}\times 1\times 3\times 2=24}
φ(72)=φ(23×32)=23−1(2−1)×32−1(3−1)=22×1×3×2=24
③ 若n为质数,则有
④ 若a为质数,b%a==0,φ(ab)=a*φ(b)
代码
//直接求
int Euler(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;
}
//线性筛法
void getphi(int N){
phi[1]=1;
for(int i=2;i<=N;i++){
if(!mark[i]){ //是素数
prime[++tot]=i;
phi[i]=i-1; //性质③
}
for(int j=1;j<=tot;j++){
if(i*prime[j]>N) break;
mark[i*prime[j]]=1;//标记i*prime[j]不是素数
if(i%prime[j]==0){//性质④
phi[i*prime[j]]=phi[i]*prime[j];break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];//性质①
}
}
}
Ⅵ 同余定理
概念
给定一个正整数m,如果两个整数a和b满足:a-b能够被m整除,即( a - b ) / m得到一个整数,那么就称整数a与b对模m同余,记作a ≡ b ( mod m )。对模m同余是整数的一个等价关系。
例如:9-5能被2整除,所以9 ≡ 5 ( mod 2) ,就是9跟5除以2得到的余数相等
性质
① 对称性:若a ≡ b ( mod m ),则b ≡ a ( mod m )
② 同余式相加:若a ≡ b ( mod m ),c ≡ d ( mod m ),则a ± c ≡ b ± d ( mod m )
③ 同余式相乘:若a ≡ b ( mod m ),c ≡ d ( mod m ),则a * c ≡ b d ( mod m )
Ⅶ 费马小定理
概念
假如
a
a
a是一个整数,
p
p
p是一个质数,那么
a
p
−
a
a^{p}-a
ap−a是
p
p
p的倍数,可以表示为
a
p
≡
a
(
m
o
d
p
)
a^{p}\equiv a{\pmod {p}}
ap≡a(modp)
如果a不是p的倍数,这个定理也可以写成
a
p
−
1
≡
1
(
m
o
d
p
)
a^{{p-1}}\equiv 1{\pmod {p}}
ap−1≡1(modp)这个书写方式更加常用。
应用
① 计算2100除以13的余数
余数为3
② 证明:对于任意整数而言,a13-a恒为2730的倍数。
Ⅷ 欧拉定理——数论定理
(→_→)该定理被认为是数学世界中最美妙的定理之一///欧拉定理实际上是费马小定理的推广//欧拉好腻害!
概念
若n,a为正整数,且n,a互质,则有
比如,令a = 3,n = 5
比5小的正整数中与5互素的数有1、2、3和4,所以φ(5)=4
代入公式可得:a{φ(n)} = 34 = 81
且 81= 80 + 1 Ξ 1 (mod 5)
应用
① 简化幂的模运算
如:计算7222的个位数,即:求7222被10除的余数。
7和10互质,且φ(10)=4
由欧拉定理知:74 Ξ 1(mod 10)
所以7222=(74)55*(72)Ξ155*72Ξ 49 Ξ 9 (mod 10)。
乘法逆元
概念
乘法逆元,是指数学领域群G中任意一个元素a,都在G中有唯一的逆元a‘,具有性质a × a’ = a’ × a = e,其中e为该群的单位元。
扩展欧几里得算法
概念
▶ 给定2个整数a、b,必存在整数x、y使满足贝祖等式:
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax + by = gcd(a,b)
ax+by=gcd(a,b)
▶ 如果a是负数,可以把问题转化成
∣
a
∣
(
−
x
)
+
b
y
=
gcd
(
∣
a
∣
,
b
)
(
∣
a
∣
\left|a\right|(-x)+by=\gcd(|a|,b)(\left|a\right|
∣a∣(−x)+by=gcd(∣a∣,b)(∣a∣为a的绝对值),然后令
x
′
=
(
−
x
)
x'=(-x)
x′=(−x)
举例
在标准的欧几里得算法中,我们记欲求最大公约数的两个数为
a
,
b
a,b
a,b,第
i
i
i步带余除法得到的商为
q
i
q_i
qi,余数为
r
i
+
1
{\displaystyle r_{i+1}}
ri+1,则欧几里得算法可以写成如下形式:
当某步得到的 r i + 1 = 0 {\displaystyle r_{i+1}=0} ri+1=0时,计算结束。上一步得到的 r i {\displaystyle r_{i}} ri 即为 a , b a,b a,b的最大公约数。
扩展欧几里得算法在
q
i
,
r
i
q_i,r_i
qi,ri的基础上增加了两组序列,记作
s
i
s_{i}
si和
t
i
t_{i}
ti,并令
s
0
=
1
{\displaystyle s_{0}=1}
s0=1,
s
1
=
0
{\displaystyle s_{1}=0}
s1=0,
t
0
=
0
t_{0}=0
t0=0,
t
1
=
1
{\displaystyle t_{1}=1}
t1=1,在欧几里得算法每步计算
r
i
+
1
=
r
i
−
1
−
q
i
r
i
{\displaystyle r_{i+1}=r_{i-1}-q_{i}r_{i}}
ri+1=ri−1−qiri之外额外计算
s
i
+
1
=
s
i
−
1
−
q
i
s
i
{\displaystyle s_{i+1}=s_{i-1}-q_{i}s_{i}}
si+1=si−1−qisi和
t
i
+
1
=
t
i
−
1
−
q
i
t
i
{ t_{i+1}=t_{i-1}-q_{i}t_{i}}
ti+1=ti−1−qiti,即:
当
r
i
+
1
=
0
{\displaystyle r_{i+1}=0}
ri+1=0时,得到的s和t就是满足条件的数
下表以
a
=
240
,
b
=
46
{\displaystyle a=240},{\displaystyle b=46}
a=240,b=46为例演示了扩展欧几里得算法。所得的最大公因数是2,所得贝祖等式为
gcd
(
240
,
46
)
=
2
=
−
9
∗
240
+
47
∗
46
{\displaystyle \gcd(240,46)=2=-9*240+47*46}
gcd(240,46)=2=−9∗240+47∗46。
(感觉有点像是通过伴随矩阵求矩阵的逆,你怎么操作我就跟着你一起,后来你达到最简之后,我也就成了答案)
代码
#include <stdio.h>
struct EX_GCD
{
int s;
int t;
int gcd;
};
struct EX_GCD extended_euclidean(int a, int b)
{
struct EX_GCD ex_gcd;
if (b == 0)
{
ex_gcd.s = 1;
ex_gcd.t = 0;
ex_gcd.gcd = 0;
return ex_gcd;
}
int old_r = a, r = b;
int old_s = 1, s = 0;
int old_t = 0, t = 1;
while (r != 0)
{
int q = old_r / r;
int temp = old_r;
old_r = r;
r = temp - q * r;
temp = old_s;
old_s = s;
s = temp - q * s;
temp = old_t;
old_t = t;
t = temp - q * t;
}
ex_gcd.s = old_s;
ex_gcd.t = old_t;
ex_gcd.gcd = old_r;
return ex_gcd;
}
int main(void)
{
int a, b;
printf("Please input two integers divided by a space.\n");
scanf("%d%d", &a, &b);
if (a < b)
{
int temp = a;
a = b;
b = temp;
}
struct EX_GCD solution = extended_euclidean(a, b);
printf("%d*%d+%d*%d=%d\n", solution.s, a, solution.t, b, solution.gcd);
printf("Press any key to exit.\n");
getchar();
getchar();
return 0;
}