整除、同余
设 a a a, b b b为整数, a ≠ 0 a\neq 0 a=0 如果存在一个整数q,使得 a × q = b a\times q=b a×q=b,则 b b b能被 a a a整除,记为 a ∣ b a\mid b a∣b,且称 b b b是 a a a的倍数, a a a是 b b b的因子。
整除的几个性质:
- 传递性:如果 a ∣ b a|b a∣b且 b ∣ c b|c b∣c,则 a ∣ c a|c a∣c
- a|b且a|c等价于对于任意的整数x,y,有a|(bx+cy)
- 设m不为0,则a|b等价于ma|mb
- 设整数x,y满足下式:ax+by=1,且a|n,b|n,那么(ab)|n
- 若b=q*d+c,那么d|b的充要条件是d|c.
同余的几个性质:
- 同加性:若 a ≡ b ( m o d p ) , a\equiv b \pmod p, a≡b(modp),则 a + c ≡ b + c ( m o d p ) a+c \equiv b+c \pmod p a+c≡b+c(modp)
- 同减性:若 a ≡ b ( m o d p ) , a\equiv b \pmod p, a≡b(modp),则 a − c ≡ b − c ( m o d p ) a-c \equiv b-c \pmod p a−c≡b−c(modp)
- 同乘性:若 a ≡ b ( m o d p ) , a\equiv b \pmod p, a≡b(modp),则 a × c ≡ b × c ( m o d p ) a \times c \equiv b\times c \pmod p a×c≡b×c(modp)
- 同除性:若 a ≡ b ( m o d p ) a\equiv b \pmod p a≡b(modp),且 c ∣ a , c ∣ b , ( c , p ) = 1 c \mid a,c\mid b,(c,p)=1 c∣a,c∣b,(c,p)=1,则 a / c ≡ b / c ( m o d p ) a/c \equiv b/c \pmod p a/c≡b/c(modp)
- 同幂性:若 a ≡ b ( m o d p ) , c > 0 , a\equiv b \pmod p,c>0, a≡b(modp),c>0,则 a c ≡ b c ( m o d p ) a^c \equiv b^c \pmod p ac≡bc(modp)
- 若 a % p = x , a % q = x a\%p=x,a\%q=x a%p=x,a%q=x,且 p , q p,q p,q互质,则 a % ( p ∗ q ) = x a\%(p*q)=x a%(p∗q)=x
数论小常识:
- 若 2 2 2能整除 a a a的最末位,则 2 ∣ a 2|a 2∣a
- 若 4 4 4能整除 a a a的末两位,则 4 ∣ a 4|a 4∣a
- 若 8 8 8能整除 a a a的末三位,则 8 ∣ a 8|a 8∣a
- 若 3 3 3能整除 a a a的各位数字之和,则 3 ∣ a 3|a 3∣a
- 若 9 9 9能整除 a a a的各位数字之和,则 9 ∣ a 9|a 9∣a
- 若 11 11 11能整除 a a a的偶数位数字之和与奇数位数字之和的差,则 11 ∣ a 11|a 11∣a
- 能被 7 7 7、 11 11 11、 13 13 13整除的数的特征是:这个数的末三位与末三位以前的数字所组成数之差能被 7 7 7、 11 11 11、 13 13 13整除。
模运算
对于整数a,b,其中b不为0,求a除以b的余数,称为a模b,记为
a
%
b
a\%b
a%b.
模运算的性质:
- 分配率:模运算对加、减、乘具有分配率
( a + b ) % c = ( a % c + b % c ) % c (a+b)\%c=(a\%c+b\%c)\%c (a+b)%c=(a%c+b%c)%c
( a − b ) % c = ( a % c − b % c ) % c (a-b)\%c=(a\%c-b\%c)\%c (a−b)%c=(a%c−b%c)%c
( a ∗ b ) % c = ( a % c ∗ b % c ) % c (a*b)\%c=(a\%c*b\%c)\%c (a∗b)%c=(a%c∗b%c)%c
( a b ) % c = ( a % c ) b % c (a^b)\%c=(a\%c)^b\%c (ab)%c=(a%c)b%c - 放缩性
如果 a % b = c , d ≠ 0 a\%b=c,d \neq 0 a%b=c,d=0,则有 ( a ∗ d ) % ( b ∗ d ) = c ∗ d (a*d)\%(b*d)=c*d (a∗d)%(b∗d)=c∗d;
如果 a % b = c , d ∣ a , d ∣ b a\%b=c,d\mid a,d \mid b a%b=c,d∣a,d∣b,则 ( a / d ) % ( b / d ) = ( c / d ) (a/d)\%(b/d)=(c/d) (a/d)%(b/d)=(c/d).
根据放缩性,则除法取余有这个式子:
a / b % c = a % ( b ∗ c ) / b a/b\%c=a\%(b*c)/b a/b%c=a%(b∗c)/b
快速幂取模
已知
a
,
b
,
p
a,b,p
a,b,p为整数,求
a
b
%
p
a^b\%p
ab%p的结果。
可以用二进制倍增的思想,快速求幂。
a的b次方,可以看做是b个a相乘,b可以拆成2的幂的和,于是可以求出a的1次方,a的2次方,a的4次方,
…
\dots
…,只要b的二进制的从右数第k位为1,则a的
2
k
2^k
2k方乘到结果里即可。
代码非常短小精悍:
LL ksm(LL a,LL b,LL p)
{
LL res=1;
while(b)
{
if(b&1)res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
类似的,还有快速乘取模,也是一样运用2进制倍增的思想。
例:求
a
∗
b
%
p
a*b\%p
a∗b%p的结果,其中a,b,p都在长整型范围以内。保证p的两倍不超过长整型。
分析:如果两个大整数相乘,结果取幂,虽然结果在整型范围以内,但是中间结果可能超过长整型。
所以可以把乘法操作用快速加来代替。
void ksc(LL a,LL b,LL p) //求a*b%p
{
LL res=0; //此处要初始化为0.
a%=p;
while(b)
{
if(b&1)res=(res+a)%p;
a=(a+a)%p;
b>>=1;
}
return res;
}
有了快速乘以后,对于长整型的幂取模,我们也可以解决了。使用快速加来代替乘法即可。
例:求
a
b
%
p
a^b\%p
ab%p的结果,
a
,
b
,
p
a,b,p
a,b,p的值不超过
1
0
1
6
10^16
1016.
分析:如果使用乘法,则两个长整型数相乘,结果可能超出长整型。所以可以用快速加来代替乘法。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define LL long long int
LL a,b,c;
LL ans;
LL quickmul(LL a,LL b,LL p)
{
LL res=0;
while(b)
{
if(b&1)res=(res+a)%p;
a=(a+a)%p;
b>>=1;
}
return res;
}
LL quickpow(LL a,LL b,LL p)
{
LL res=1;
while(b)
{
if(b&1)res=quickmul(res,a,p);
a=quickmul(a,a,p);
b>>=1;
}
return res;
}
int main()
{
while(scanf("%lld%llld%lld",&a,&b,&c)!=-1,a||b||c)
{
ans=quickpow(a,b,c);
printf("%lld\n",ans);
}
return 0;
}
同余等价类、剩余系、缩系
在模意义下,每一个数表示的是一个同余等价类。比如在模3的意义下,1表示的是所有除以3余数为1的整数。所以
0
0
0表示的是
{
0
,
3
,
6
,
9
,
…
,
}
\{0,3,6,9,\dots,\}
{0,3,6,9,…,} ,
1
1
1表示的是
{
1
,
4
,
7
,
…
,
}
\{1,4,7,\dots,\}
{1,4,7,…,},而
2
2
2表示的是
{
2
,
5
,
8
,
…
,
}
\{2,5,8,\dots,\}
{2,5,8,…,}.
可以发现,在模意义下,所有的非负整数可以被分为若干同余等价类。
模p的剩余系指的是
{
0
,
1
,
2
,
…
,
p
−
1
}
\{0,1,2,\dots,p-1\}
{0,1,2,…,p−1},即小于p的所有非负整数,这个集合中包含了所有模p的余数。集合中的每一个数其实代表一个同余等价类。这个集合称为模p的剩余系,记为
Z
p
Z_p
Zp
如p为6,则
Z
p
=
{
0
,
1
,
2
,
3
,
4
,
5
}
Z_p=\{0,1,2,3,4,5\}
Zp={0,1,2,3,4,5}.
在模p的剩余系中,与p互质的数的集合,称为模p的缩系,记为
Z
p
∗
Z_p^*
Zp∗.
如p为6,则
Z
p
∗
=
{
1
,
5
}
Z_p^*=\{1,5\}
Zp∗={1,5}.
缩系又称为简化剩余系。
质数及其筛法
如果一个自然数a,只能被1和它自身整除,且不能被其他数整除,则a为质数。换句话说,质数只有两个因子。
注意:1不是质数。
100以内的质数有:2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,91,97
例1:判断一个数n是否为质数。
可以枚举
[
2
,
n
−
1
]
[2,n-1]
[2,n−1],如果n在这个范围内有因子,则n不是质数。这个方法的时间复杂度为
O
(
n
)
O(n)
O(n)
更好的方法是枚举
[
2
,
(
n
)
]
[2 ,\sqrt(n)]
[2,(n)],时间复杂度为
O
(
s
q
r
t
(
n
)
)
。
O(sqrt(n))。
O(sqrt(n))。因为n的因子是成对出现的,如果
i
∣
n
i | n
i∣n,则
n
i
∣
n
\frac n i |n
in∣n,而
i
,
n
i
i,\frac n i
i,in 必有至少一个在
[
2
,
(
n
)
]
[2,\sqrt(n)]
[2,(n)]内。
参考代码如下:
#include<bits/stdc++.h>
using namespace std;
int n;
int main()
{
scanf("%d",&n);
for(int i=2;i<=sqrt(n);i++)
if(n%i==0)
{
printf("n is not a prime\n");
return 0;
}
printf("n is a prime\n");
return 0;
}
例2:请输出
[
1
,
n
]
[1,n]
[1,n]内的所有质数。每行一个质数。n<=100000。
可以利用例1中判断质数的方法,将1~n的所有数都判断一下,如果是质数,就输出它。这种方法的时间复杂度为
O
(
n
n
)
O(n\sqrt n)
O(nn)
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int n;
bool isprime(int n)
{
for(int i=2;i*i<=n;i++)
{
if(n%i==0)return 0;
}
return 1;
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++) //将i=1排除掉。
if(isprime(i))printf("%d\n",i);
return 0;
}
这个方法还是太慢了。毕竟时间复杂度是
O
(
N
N
)
O(N\sqrt N)
O(NN)。
下面介绍两种更快的质数筛法。
埃氏筛法.
时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
算法是这样的:先把n以内的2的倍数(不包含2)全部删除,再把n以内的3的倍数(不包含3)全部删除,……,这样做下去,最后剩下的数就全部是质数。
这里的删除其实不算真的删除,只是打上一个标记而已。
每个数都会被它的质因子打一次标记,而一个数的质因子个数不超过log,所以,这个时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)
代码参考如下:
#include<iostream>
using namespace std;
#define MAXN 1000005
bool flgs[MAXN];//flgs[i]==0表示i为质数 不考虑i<2的情况
int n,cnt,primes[MAXN];
void getprime(int n)
{
for(int i=2;i<=n;i++)
{
if(flgs[i]==1)continue;
primes[cnt++]=i;
for(int j=i;j<=n/i;j++)
flgs[j*i]=1;
}
}
int main()
{
scanf("%d",&n);
getprime(n);
for(int i=0;i<cnt;i++)
printf("%d\n",primes[i]);
return 0;
}
欧式筛法
在上述的埃氏筛法中,一个数可能被它的各个质因子都筛了一遍,而一个数在质因子是不会超过
l
o
g
N
logN
logN的,所以时间复杂度为
O
(
N
l
o
g
N
)
O(NlogN)
O(NlogN)。而欧式筛法保证每个数只被它的最小质因子筛一遍,这样,时间复杂度为
O
(
N
)
O(N)
O(N)。
欧式筛法的过程是这样的:
有一个质数集合Q,一开始,质数集合为空,将最小的质数2加入集合。此时
Q
=
{
2
}
Q=\{2\}
Q={2}
从2开始枚举依次枚举倍数a,如果倍数a为质数,即将a加入集合Q。
将质数集合中的每个质数的a倍都删掉,因为这些数都是合数。删除指的是打上删除标记,不需要真的删除掉。显然,未打删除标记的数都是质数了。
比如当前质数集合为
Q
=
{
p
1
,
p
2
,
…
,
p
k
}
Q=\{p_1,p_2,\dots,p_k\}
Q={p1,p2,…,pk},当前枚举到的倍数为
a
a
a,如果a没有删除标记,则a为质数,先将a加入集合Q。接下来枚举质数集合中的所有质数,则将
a
∗
p
1
,
a
∗
p
2
,
…
,
a
∗
p
k
a*p_1,a*p_2,\dots,a*p_k
a∗p1,a∗p2,…,a∗pk全部打上删除标记。
在当前倍数为a,枚举质数的过程中,若发现a是某个质数
p
i
p_i
pi的倍数时,此时后续的质数就无需再枚举了,可以提前退出。为什么呢?设后续的质数为
p
i
′
,
(
p
i
′
>
p
i
)
p_{i'},(p_{i'}>p_i)
pi′,(pi′>pi),那么那些质数的a倍,其实也是质数
p
i
p_i
pi的倍数。即
a
∗
p
i
′
=
a
′
∗
p
i
a*p_{i'}=a'*p_i
a∗pi′=a′∗pi,因为p_i<p_{i’},所以,
a
′
>
a
a'>a
a′>a。因为我们要保证每一个数是被它的最小质因子给删掉,
a
∗
p
i
′
a*p_{i'}
a∗pi′应该被
p
i
p_i
pi删掉,所以就留给倍数a变成
a
′
a'
a′再去处理了。
例:求给一个整数n,输出区间[1,n]中的所有质数。
n<=1000000
参考代码如下:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
int prime[MAXN];
bool delflg[MAXN];
int n,cnt;
void sieve(int x)
{
for(int i=2;i<=x;i++)
{
if(delflg[i]==0)prime[cnt++]=i;
for(int j=0;j<cnt;j++)
{
if(prime[j]*i>x)break;
delflg[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
int main()
{
scanf("%d",&n);
sieve(n);
for(int i=0;i<cnt;i++)
{
printf("%d\n",prime[i]);
}
return 0;
}
例1:给出一个整数
n
n
n,求
n
n
n^n
nn的最低位的值。
n
<
=
1
0
16
n<=10^{16}
n<=1016
分析:本题即是求
n
n
n^n
nn模10的结果。
HDU1061
参考代码略。
例2:给出一个整数n,求有多少个整数k,满足k^k<n.
1
≤
n
≤
1
0
18
1\leq n\leq 10^{18}
1≤n≤1018
分析:观察到k其实很小。所以可以直接枚举k,求k的快速幂。
但是因为
n
n
n很大,所以k的快速幂可能会溢出。
注意:溢出不一定为负数。
本题可以打表,可以发现k不大于15.
如果不大表,一定要防止溢出。因为溢出过后,实际值一定是超过了n的。但是如何发现它溢出了呢?
可以再用除法检测一下。
参考代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long int
LL qpow(LL a,LL b)
{
LL res=1,tmp;
while(b)
{
if(b&1)
{
tmp=res;
res=res*a;
if(a==0||res/a!=tmp)return 0;
}
tmp=a;
a=a*a;
if(a/tmp!=tmp)return 0;
b>>=1;
}
return res;
}
LL n;
int main()
{
while(cin>>n)
{
LL lz=1;
while(1)
{
LL res=qpow(lz,lz);
if(res>n||res<=0)break;
lz++;
}
cout<<lz-1<<endl;
}
return 0;
}
例3:有一个n的排列,如果存在一个位置
1
<
=
i
<
=
n
1<=i<=n
1<=i<=n,使得前
i
i
i个数单调递增或递减,第
i
+
1
i+1
i+1个数到第
n
n
n个数也单调递增或递减。则称它为漂亮的。问漂亮的n排列有多少个?你只需要输出答案模
p
p
p的结果。
1
≤
n
,
p
≤
1
0
18
1\leq n,p\leq10^{18}
1≤n,p≤1018
source:hdu5187
分析:可以找规律,得到递推式为
a
n
s
=
2
n
−
2
ans=2^n-2
ans=2n−2.
这个式子其实也可以推出来。
先考虑从大到小依次选择这n个数来摆放。从第二个数开始,它只能放在已放好的那些数的左边或右边,这样形成的是一个单峰的排列。一共有
2
n
−
1
2^{n-1}
2n−1种。这里边包含了所有元素单调递增或所有元素单调递减的排列。
单谷排列也类似的,只需要由小到大选择这n个数即可。摆放的方法是一样的。这又有
2
n
−
1
2^{n-1}
2n−1种。然后其中也包含了单调递增或单调递减这两种方案,这两种在单峰排列中已经算过了。
所以答案
a
n
s
=
2
∗
2
n
−
1
−
2
=
2
n
−
2
ans=2*2^{n-1}-2=2^n-2
ans=2∗2n−1−2=2n−2
考虑一下特殊的几种情况:比如p=1或n=1等等。
然后因为
n
,
p
n,p
n,p都是长整型,所以快速幂可能爆长整型,要用快速加来代替乘法。
参考代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define LL long long int
LL n,p;
LL qmul(LL a,LL b,LL p)
{
LL res=0;
while(b)
{
if(b&1)res=(res+a)%p;
a=(a+a)%p;
b>>=1;
}
return res;
}
LL qpow(LL n,LL p)
{
LL res=1,a=2;
while(n)
{
if(n&1)res=qmul(res,a,p);
a=qmul(a,a,p);
n>>=1;
}
return res;
}
int main()
{
while(scanf("%lld%lld",&n,&p)!=-1)
{
if(p==1)printf("0\n");
else if(n==1)printf("%d\n",n);
else printf("%lld\n",(qpow(n,p)+p-2)%p);
}
return 0;
}
例4:给两个整数n和k,令
f
(
i
)
=
i
k
f(i)=i^k
f(i)=ik,求
f
(
1
)
+
f
(
2
)
+
⋯
+
f
(
n
)
f(1)+f(2)+\dots+f(n)
f(1)+f(2)+⋯+f(n)的值。这个值可能很大,你只需要输出结果模
1
0
9
+
7
10^9+7
109+7的值。最多有T组数据。
1
<
=
n
<
=
10000
,
0
<
=
k
<
=
5
,
T
<
=
20
1<=n<=10000,0<=k<=5,T<=20
1<=n<=10000,0<=k<=5,T<=20
分析:k很小,直接模拟即可。
例5:给出n对整数a和b,和一个模数m,求
(
a
1
b
1
+
a
2
b
2
+
⋯
+
a
k
b
k
)
%
m
(a_1^{b_1}+a_2^{b_2}+\dots+a_k^{b_k})\%m
(a1b1+a2b2+⋯+akbk)%m的值。
poj1995
最大公约数与最小公倍数
一般的,设
a
1
,
a
2
,
a
3
,
…
,
a
k
a_1,a_2,a_3,\dots,a_k
a1,a2,a3,…,ak是
k
k
k个正整数,如果存在一个正整数
d
d
d,使得
d
∣
a
1
,
d
∣
a
2
,
…
d
∣
a
k
d| a_1,d\mid a_2,\dots d|a_k
d∣a1,d∣a2,…d∣ak,那么
d
d
d则为
a
1
,
a
2
,
…
,
a
k
a_1,a_2,\dots,a_k
a1,a2,…,ak的公约数。在所有公约数中,最大的称为最大公约数,记为
g
c
d
(
a
1
,
a
2
,
…
,
a
k
)
gcd(a_1,a_2,\dots,a_k)
gcd(a1,a2,…,ak),显然它是存在的,至少为1。当
g
c
d
=
1
gcd=1
gcd=1时,称这
n
n
n个数是互质的或既约的。公约数一定是最大公约数的约数。
一般的,设
a
1
,
a
2
,
a
3
,
…
…
a
k
a_1,a_2,a_3,……a_k
a1,a2,a3,……ak是
k
k
k个正整数,如果存在一个正整数
d
d
d,使得
a
1
∣
d
,
a
2
∣
d
,
a
3
∣
d
,
…
…
a
k
∣
d
a_1|d,a_2|d,a_3|d,……a_k|d
a1∣d,a2∣d,a3∣d,……ak∣d,那么
d
d
d则为
a
1
,
a
2
,
…
…
a
k
a_1,a_2,……a_k
a1,a2,……ak的公倍数,其中最小的称为最小公倍数数,记为
l
c
m
(
a
1
,
a
2
,
…
…
,
a
k
)
lcm(a1,a2,……,ak)
lcm(a1,a2,……,ak),显然它是存在的。公倍数一定是最小公倍数的倍数。
定理:
l
c
m
(
a
,
b
)
×
g
c
d
(
a
,
b
)
=
a
×
b
lcm(a,b) \times gcd(a,b)=a \times b
lcm(a,b)×gcd(a,b)=a×b
证明:将
a
,
b
a,b
a,b进行质因子分解,设
a
,
b
a,b
a,b的质因子集合并集为
{
p
1
,
p
2
,
…
,
p
n
}
\{p_1,p_2,\dots,p_n\}
{p1,p2,…,pn}。
设
a
=
p
1
k
1
p
2
k
2
…
p
n
k
n
a=p_1^{k_1}p_2^{k_2}\dots p_n^{k_n}
a=p1k1p2k2…pnkn 其中
0
≤
k
1
,
0
≤
k
2
,
0
≤
k
3
,
…
0
≤
k
n
0\leq k_1,0\leq k_2,0\leq k_3,\dots 0\leq k_n
0≤k1,0≤k2,0≤k3,…0≤kn
b
=
p
1
j
1
p
2
j
2
…
p
n
j
n
b=p_1^{j_1}p_2^{j_2}\dots p_n^{j_n}
b=p1j1p2j2…pnjn 其中
0
≤
j
1
,
0
≤
j
2
,
0
≤
j
3
,
…
,
0
≤
j
n
0\leq j_1,0\leq j_2, 0\leq j_3,\dots,0\leq j_n
0≤j1,0≤j2,0≤j3,…,0≤jn
那么显然
g
c
d
(
a
,
b
)
=
p
1
m
i
n
(
k
1
,
j
1
)
p
2
m
i
n
(
k
2
,
j
2
)
…
p
n
m
i
n
(
k
n
,
j
n
)
gcd(a,b)=p_1^{min(k_1,j_1)}p_2^{min(k_2,j_2)}\dots p_n^{min(k_n,j_n)}
gcd(a,b)=p1min(k1,j1)p2min(k2,j2)…pnmin(kn,jn)
l
c
m
(
a
,
b
)
=
p
1
m
a
x
(
k
1
,
j
1
)
p
2
m
a
x
(
k
2
,
j
2
)
…
p
n
m
a
x
(
k
n
,
j
n
)
lcm(a,b)=p_1^{max(k_1,j_1)}p_2^{max(k_2,j_2)}\dots p_n^{max(k_n,j_n)}
lcm(a,b)=p1max(k1,j1)p2max(k2,j2)…pnmax(kn,jn)
∵
m
i
n
(
k
i
,
j
i
)
+
m
a
x
(
k
i
,
j
i
)
=
k
i
+
j
i
\because min(k_i,j_i)+max(k_i,j_i)=k_i+j_i
∵min(ki,ji)+max(ki,ji)=ki+ji
∴
g
c
d
(
a
,
b
)
∗
l
c
m
(
a
,
b
)
=
p
1
k
1
+
j
1
∗
p
2
k
2
+
j
2
…
p
n
k
n
+
j
n
=
a
∗
b
\therefore gcd(a,b)*lcm(a,b)=p_1^{k_1+j_1}*p_2^{k_2+j_2}\dots p_n^{k_n+j_n}=a*b
∴gcd(a,b)∗lcm(a,b)=p1k1+j1∗p2k2+j2…pnkn+jn=a∗b
辗转相除法
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
gcd(a,b)=gcd(b,a\%b)
gcd(a,b)=gcd(b,a%b)
证明:
设
g
c
d
(
a
,
b
)
=
P
,
则
a
=
k
P
,
b
=
g
P
,
g
c
d
(
b
,
a
gcd(a,b)=P,则a=kP,b=gP,gcd(b,a%
gcd(a,b)=P,则a=kP,b=gP,gcd(b,a
更相减损术的证明方法和辗转相除法差不多。
中国古代,九章算术中提到了一种求最大公约数的方法,即更相减损术。
如果要对分式
a
/
b
a/b
a/b约分,如果a,b都是偶数,可以将a,b都折半;否则,将a和b交替地减去对方,直到最后两者相等,那么这个数可以做为原来a,b的最大公约数。
int gcd(int a,int b)
{
if(a%b==0)return b;
return gcd(b,a%b);
}
裴蜀定理
如果
a
,
b
a,b
a,b的最大公约数为
d
d
d,且d能整除c,则存在正整数x和y,满足ax+by=c。
证明:
令
a
′
=
a
/
d
,
b
′
=
b
/
d
,
则
a
′
x
+
b
′
y
=
1
a'=a/d,b'=b/d,则a'x+b'y=1
a′=a/d,b′=b/d,则a′x+b′y=1,此时,
a
′
,
b
′
a',b'
a′,b′互质。即我们只需要证明:对于互质的两个整数
a
′
,
b
′
a',b'
a′,b′,必存在一个整数
x
x
x,满足
a
′
x
%
b
′
=
1
a'x\%b'=1
a′x%b′=1 即可。 (1)
引理一:如果
a
,
b
a,b
a,b为正整数,且
a
,
b
a,b
a,b互质,则不存在小于
b
b
b的正整数k,使得
0
≡
k
∗
a
(
m
o
d
b
)
0 \equiv k*a \pmod b
0≡k∗a(modb)
证明显然。用反证法,如果存在
0
<
k
<
b
0<k<b
0<k<b,满足
0
≡
k
∗
a
(
m
o
d
b
)
0 \equiv k*a \pmod b
0≡k∗a(modb)。
根据整数唯一分解定理,
k
∗
a
k*a
k∗a中一定包含
b
b
b的所有质因子,而
a
a
a与
b
b
b互质,
a
a
a中不可能包含
b
b
b中的质因子,所以必然k是b的倍数。而
0
<
k
<
b
0<k<b
0<k<b,所以,
k
k
k不可能包含
b
b
b中所有质因子。
推论:如果
a
,
b
a,b
a,b为正整数,且
a
,
b
a,b
a,b互质,
0
,
a
,
2
∗
a
,
3
∗
a
,
…
,
(
b
−
1
)
∗
a
0,a,2*a,3*a,\dots,(b-1)*a
0,a,2∗a,3∗a,…,(b−1)∗a,这些数模b,余数互不相等。
证明:如果存在两个不同的数设为
i
∗
a
,
j
∗
a
i*a,j*a
i∗a,j∗a,它们模
b
b
b的余数相等,则
(
i
−
j
)
∗
a
%
b
(i-j)*a\%b
(i−j)∗a%b模b的余数为
0
0
0。
而因为
0
<
i
<
n
,
0
<
j
<
n
0 \lt i \lt n,0 \lt j \lt n
0<i<n,0<j<n,假设
i
>
j
i>j
i>j,则
0
<
(
i
−
j
)
<
n
0 \lt (i-j)\lt n
0<(i−j)<n,这与引理一矛盾。
得证。
引理二:如果
a
,
b
a,b
a,b互质,则必存在一个整数
k
k
k,满足
k
∗
a
%
b
=
1
k*a\%b=1
k∗a%b=1.
证明:根据推论,这些数模b的结果只能是集合
{
0
,
1
,
…
b
−
1
}
\{0,1,\dots\,b-1\}
{0,1,…b−1}中的数,而这些结果互不相等,且有b个,所以其中必有一个为1。
根据引理2,如果
a
,
b
a,b
a,b互质,则必存在一个整数
k
k
k,满足
k
∗
a
%
b
=
1
k*a\%b=1
k∗a%b=1,即
k
∗
a
−
p
∗
b
=
1
k*a-p*b=1
k∗a−p∗b=1
于是,裴蜀定理得证。