【题目链接】
ybt 1915:【01NOIP普及组】最大公约数与最小公倍数
洛谷 P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题
【题目考点】
1. 最大公约数与最小公倍数
- 求最大公约数的方法:见信息学奥赛一本通 1207:求最大公约数问题 | OpenJudge 2.2 7592:求最大公约数问题
- 最大公约数与最小公倍数的关系:两数乘积为这两数最大公约数与最小公倍数的乘积
【解题思路】
解法1:枚举
已知两个正整数x,y。x是p,q两个数的最大公约数,y是p,q两个数的最小公倍数。
因为两数乘积是最大公约数与最小公倍数的乘积,所以有:
x
y
=
p
q
xy = pq
xy=pq
p,q这两个数字,一定都大于等于最大公约数x,小于等于最小公倍数y。
从x到y枚举p,通过
q
=
x
y
/
p
q = xy/p
q=xy/p得到q。
求出p,q的最大公约数,看最大公约数的值是否等于x。如果是,那么这一组p, q是满足条件的,做计数。否则不满足条件。
最后输出满足条件的p, q的个数。
复杂度:如果x、y中较大的值为n,复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
解法2:分解质因数
p,q的最大公约数是x,最小公倍数是y。
显然四个数字都是x的倍数,将每个数字分别除以x,四个数字变为:
p/x, q/x, 1, y/x
此时p/x与q/x的最大公约数是1(即互质),最小公倍数是y/x。
互质数字的最小公倍数,就是两个数字相乘,即:
p
/
x
∗
q
/
x
=
y
/
x
p/x * q/x = y/x
p/x∗q/x=y/x。
(该式也可以通过
p
q
=
x
y
pq=xy
pq=xy直接推出)
将y/x分解质因数,得到
y
/
x
=
a
1
b
1
a
2
b
2
.
.
.
a
n
b
n
y/x=a_1^{b_1}a_2^{b_2}...a_n^{b_n}
y/x=a1b1a2b2...anbn,其中
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1,a2,...,an都是y/x的质因数。
此时要做的就是将这些质因数分配给
p
/
x
p/x
p/x与
q
/
x
q/x
q/x两个数字。
由于
p
/
x
p/x
p/x与
q
/
x
q/x
q/x互质,因此二者不可能有相同的因数。相同的质因数只能分配给二者中的一个数字。
对于
a
1
b
1
a_1^{b_1}
a1b1,可以分给
p
/
x
p/x
p/x或
q
/
x
q/x
q/x,有两种选择。
对于
a
2
b
2
a_2^{b_2}
a2b2,可以分给
p
/
x
p/x
p/x或
q
/
x
q/x
q/x,有两种选择。
。。。
对于
a
n
b
n
a_n^{b_n}
anbn,可以分给
p
/
x
p/x
p/x或
q
/
x
q/x
q/x,有两种选择。
n是
y
/
x
y/x
y/x的质因数种类数。
根据分步原理,
p
/
x
p/x
p/x与
q
/
x
q/x
q/x,即
p
p
p与
q
q
q的总情况数为
2
n
2^n
2n,
可以使用快速幂。
复杂度:如果x、y中较大的值为n,复杂度为
O
(
l
o
g
n
)
O(log\sqrt{n})
O(logn)
【题解代码】
解法1:枚举
- 写法1:使用迭代方法求最大公约数
#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)//求a, b的最大公约数。注意必须满足a >= b
{
int r;
while(b > 0)
{
r = a % b;
a = b;
b = r;
}
return a;
}
int main()
{
int x, y, p, q, ct = 0, x1;
cin >> x >> y;
for(p = x; p <= y; ++p)
{
if(x*y%p == 0)
{
q = x*y/p;
x1 = gcd(p, q);//求出p, q的最大公约数x1
if(x1 == x)//如果与x相同,那么这一组p, q满足条件
ct++;
}
}
cout << ct;
return 0;
}
- 写法2:使用递归方法求最大公约数
#include<bits/stdc++.h>
using namespace std;
int gcd(int a, int b)//求a, b的最大公约数。注意必须满足a >= b
{
if(b == 0)
return a;
return gcd(b, a%b);
}
int main()
{
int x, y, p, q, ct = 0;
cin >> x >> y;
for(p = x; p <= y; ++p)
if(x*y%p == 0 && gcd(p, x*y/p) == x)
ct++;
cout << ct;
return 0;
}
解法2:分解质因数
#include <bits/stdc++.h>
using namespace std;
int count(int n)//求n中因数种类数
{
int ct = 0;
for(int i = 2; i*i <= n; ++i)
{
if(n%i == 0)
{
ct++;
while(n%i == 0)
n /= i;
}
}
if(n > 1)
ct++;
return ct;
}
int fastPow(int a, int b)//快速幂
{
int r = 1;
while(b > 0)
{
if(b % 2 == 1)
r *= a;
a *= a;
b /= 2;
}
return r;
}
int main()
{
int x, y;
cin >> x >> y;
if(y%x == 0)
cout << fastPow(2, count(y/x)) << endl;
else
cout << 0 << endl;
return 0;
}