信息学奥赛一本通 1915:【01NOIP普及组】最大公约数与最小公倍数 | 洛谷 P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

【题目链接】

ybt 1915:【01NOIP普及组】最大公约数与最小公倍数
洛谷 P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题

【题目考点】

1. 最大公约数与最小公倍数

【解题思路】

解法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/xq/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;
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值