最大公约数gcd
一些结论积累
- 引理:若正整数
a
+
b
=
c
a+b=c
a+b=c,则
a
a
a 与
b
b
b 互质的充要条件是
a
a
a 与
c
c
c 互质。
证明: 先证充分性,如果 gcd ( a , b ) = 1 \operatorname{gcd}(a, b)=1 gcd(a,b)=1,而反证设 gcd ( a , c ) = u > 1 \operatorname{gcd}(a, c)=u>1 gcd(a,c)=u>1,则 b = c − a b=c-a b=c−a 也是 u u u 的倍数,矛盾。再证必要性,如果 gcd ( a , c ) = 1 \operatorname{gcd}(a, c)=1 gcd(a,c)=1,而 gcd ( a , b ) = u > 1 \operatorname{gcd}(a, b)=u>1 gcd(a,b)=u>1,同理 c = a + b c=a+b c=a+b 是 u u u 的倍数,矛盾。 - ∀ a , b ∈ N , a ≥ b , 有 g c d ( a , b ) = g c d ( b , a − b ) = g c d ( a , a − b ) \forall a,b\in N,a\ge b,有gcd(a,b)=gcd(b,a-b)=gcd(a,a-b) ∀a,b∈N,a≥b,有gcd(a,b)=gcd(b,a−b)=gcd(a,a−b).
- ∀ a , b ∈ N , 有 g c d ( 2 a , 2 b ) = 2 g c d ( a , b ) \forall a,b\in N,有gcd(2a,2b)=2gcd(a,b) ∀a,b∈N,有gcd(2a,2b)=2gcd(a,b).
- ∀ a , b ∈ N , b ≠ 0 , 有 g c d ( a , b ) = g c d ( b , a % b ) \forall a,b\in N,b\ne 0,有gcd(a,b)=gcd(b,a\% b) ∀a,b∈N,b=0,有gcd(a,b)=gcd(b,a%b).
九章算术·更相减损术
∀
a
,
b
∈
N
,
a
≥
b
,
有
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
−
b
)
=
g
c
d
(
a
,
a
−
b
)
\forall a,b\in N,a\ge b,有gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)
∀a,b∈N,a≥b,有gcd(a,b)=gcd(b,a−b)=gcd(a,a−b).
∀
a
,
b
∈
N
,
有
g
c
d
(
2
a
,
2
b
)
=
2
g
c
d
(
a
,
b
)
\forall a,b\in N,有gcd(2a,2b)=2gcd(a,b)
∀a,b∈N,有gcd(2a,2b)=2gcd(a,b).
欧几里得算法(辗转相除法)
∀ a , b ∈ N , b ≠ 0 , 有 g c d ( a , b ) = g c d ( b , a % b ) \forall a,b\in N,b\ne 0,有gcd(a,b)=gcd(b,a\% b) ∀a,b∈N,b=0,有gcd(a,b)=gcd(b,a%b).
定理:设
a
=
q
b
+
r
a=qb+r
a=qb+r,其中
a
a
a,
b
b
b,
q
q
q,
r
r
r都是正整数,则有:
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
r
)
=
g
c
d
(
a
,
r
)
gcd(a,b)=gcd(b,r)=gcd(a,r)
gcd(a,b)=gcd(b,r)=gcd(a,r).
基于上述定理,用代码实现如下:
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
//或者:
int gcd(int a,int b)
{
if(a==0) return b;
return gcd(b%a,a);
}
//或:
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
算法复杂度:
拉梅定理:用辗转相除法计算两个正整数的最大公因子时,所需的除法次数不会超过两个整数较小的那个数的倍数的5倍。
有时,也可以直接使用C语言的库函数__gcd()。
相关题目:
华华对月月的忠诚
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a,b,n;
signed main()
{
scanf("%lld %lld %lld",&a,&b,&n);
int ans=__gcd(a,b);
printf("%lld\n",ans);
}
好题:求 x x x使得 a ≡ b ≡ c ( m o d x ) a\equiv b \equiv c\pmod x a≡b≡c(modx)
当
a
=
b
=
c
a=b=c
a=b=c时,会有无穷解。
否则,答案就是
g
c
d
(
b
−
a
,
c
−
b
)
gcd(b-a,c-b)
gcd(b−a,c−b)的因子,假设
a
<
=
b
<
=
c
a<=b<=c
a<=b<=c.
感性认知:一个数%x的结果=这个数+y%x的结果,当且仅当x是y的因子。
#include <bits/stdc++.h>
using namespace std;
int t,a[3];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d%d",a+0,a+1,a+2);
if(a[0]==a[1] && a[1]==a[2]) {
printf("-1\n");
}
else {
sort(a,a+3);
vector<int> v;
int gcd=__gcd(a[1]-a[0],a[2]-a[1]);
for(int i=1;i*i<=gcd;++i) {
if(gcd%i==0){
v.push_back(i);
if(gcd/i!=i) v.push_back(gcd/i);
}
}
sort(v.begin(),v.end());
for(auto x:v) printf("%d ",x);
printf("\n");
}
}
}
最小公倍数lcm
性质:
- $ {\textstyle \sum_{i=1}^{n}} {\textstyle \sum_{j=1}^{n}}[lcm(i,j)=n]= {\textstyle \prod_{i=1}^{k}}(2e_i+1)$
例题:LightOJ-1236 Pairs Forming LCM
题意:求解
l
c
m
(
i
,
j
)
=
n
lcm(i,j)=n
lcm(i,j)=n的
(
i
,
j
)
(i,j)
(i,j)对数,
(
i
≤
j
)
(i\le j)
(i≤j)。
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
//线筛 筛出 1e7内所有质因子
const int N=1e7+1;
int cnt=0,pri[N];
bool v[N];
void prime(int n){
for(int i=2;i<=n;++i){
if(!v[i]){
v[i]=i;
pri[++cnt]=i;
}
for(int j=1;pri[j]<=n/i;++j){
v[pri[j]*i]=pri[j];
if(i%pri[j]==0) break;
}
}
}
int cal(int n){
int ans=1;
for(int i=1;i<=cnt;++i){
if(pri[i]>n) break;
if(n%pri[i]==0){
int num=0;
while(n%pri[i]==0) num++,n/=pri[i];
ans*=(num*2+1);
}
}
if(n>1) ans*=3;
return ans;
}
int T,n,cs;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
prime(N-1);
cin>>T;
while(T--){
cin>>n;
int ans=(cal(n)+1)/2;
cout<<"Case "<<(++cs)<<": "<<ans<<'\n';
}
}
这道题数据比较大(ull),当数据较大时,可以考虑先除后乘。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int a,b;
signed main()
{
scanf("%lld %lld",&a,&b);
int d=__gcd(a,b);
int ans=a/d*b;
printf("%lld\n",ans);
}
从这道题,我们也可以看出,__gcd()可以求很大的数。
最大公约数 和 最小公倍数 的关系
- ∀ a , b ∈ N , g c d ( a , b ) ∗ l c m ( a , b ) = a ∗ b \forall a,b\in N,gcd(a,b)*lcm(a,b)=a*b ∀a,b∈N,gcd(a,b)∗lcm(a,b)=a∗b.
- 定理:对于正整数 a , b a,b a,b,设 g c d ( a , b ) = k gcd(a,b)=k gcd(a,b)=k,则存在 g c d ( a / k , b / k ) = 1 gcd(a/k,b/k)=1 gcd(a/k,b/k)=1.
- 定理:对于正整数 a , b a,b a,b,设 l c m ( a , b ) = k lcm(a,b)=k lcm(a,b)=k,则存在 g c d ( k / a , k / b ) = 1 gcd(k/a,k/b)=1 gcd(k/a,k/b)=1.
设某未知正整数
x
x
x满足:
x
x
x和
a
0
a0
a0的最大公约数是
a
1
a1
a1;
x
x
x和
b
0
b0
b0的最小公倍数是
b
1
b1
b1。
求满足条件的
x
x
x个数。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,a0,a1,b0,b1;
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld%lld%lld%lld",&a0,&a1,&b0,&b1);
int ans=0;
int t1=a0/a1;
int t2=b1/b0;
for(int i=1;i*i<=b1;++i)
{
if(b1%i==0)
{
if(i%a1==0 && __gcd(i/a1,t1)==1 && __gcd(b1/i,t2)==1) ans++;
int t=b1/i;
if(t==i) continue;
if(t%a1==0 && __gcd(t/a1,t1)==1 && __gcd(b1/t,t2)==1) ans++;
}
}
printf("%lld\n",ans);
}
}