洛谷千题详解 | P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题【C++语言】

博主主页:Yu·仙笙

专栏地址:洛谷千题详解

目录

题目描述

输入格式

输出格式

输入输出样例

解析:

C++源码:

C++源码2:

C++源码3:


-------------------------------------------------------------------------------------------------------------------------------- 

 --------------------------------------------------------------------------------------------------------------------------------

题目描述

输入两个正整数x0​,y0​,求出满足下列条件的 P, Q 的个数:

  1. P,Q 是正整数。

  2. 要求 P, Q 以x0​ 为最大公约数,以 y0​ 为最小公倍数。

试求:满足条件的所有可能的 P, Q 的个数。

 --------------------------------------------------------------------------------------------------------------------------------

输入格式

一行两个正整数x0​,y0​。

 --------------------------------------------------------------------------------------------------------------------------------

输出格式

一行一个数,表示求出满足条件的 P, Q 的个数。

 --------------------------------------------------------------------------------------------------------------------------------

输入输出样例

输入 #1复制

3 60

输出 #1复制

4

 --------------------------------------------------------------------------------------------------------------------------------

解析:

upd on 2020/06/12:修改了部分解释不够清楚和有歧义的地方。
upd on 2022/07/21:添加了 Latex。

前置知识

  • 最大公约数(即 \gcdgcd) 和最小公倍数(即 \operatorname{lcm}lcm)的求法。

该题的关键点在于,两个数的积等于它们最大公约数和它们最小公倍数的积。公式表示为 a\times b=\gcd(a,b) \times \operatorname{lcm}(a,b)a×b=gcd(a,b)×lcm(a,b)。设作为答案的两个数为 xx 和 yy,我们要使它们同时满足以下三个条件,并统计这样的 xx 和 yy 的个数(P,QP,Q 含义见题目描述):

  • x \times y=P \times Qx×y=P×Q
  • \gcd(x,y)=Pgcd(x,y)=P
  • \operatorname{lcm}(x,y)=Qlcm(x,y)=Q

我们可以枚举 xx,判断是否存在满足条件 11 的整数 yy(即,xx 能否被 P,QP,Q 的积整除)。满足第一个条件后,再分别判断当前的 x,yx,y 是否能够同时满足另外两个条件即可。显然,这种做法会超时。

考虑优化这个程序。我们其实并不需要枚举两次,因为对于不同的 x,yx,y ,交换它们的值一定可以得到另一组与之对应的解。因此,从 11 到 \sqrt{P\times Q}P×Q​ 枚举一遍,每发现一组答案就将 ansans 的值加上 22 即可。

一组 x,yx,y 有对应解时有条件:x,yx,y 的值不同。如果它们相同,交换后并不能得到与之对应的另一组数。当 x=yx=y 时,易得 x=y=\gcd(x,y)=\operatorname{lcm}(x,y)x=y=gcd(x,y)=lcm(x,y)。 所以要对此进行特判,若 P,QP,Q 相等,这种情况就存在, ansans 里要减去 11。

一些代码实现技巧:

  • c++ 里有一个自带的求 \gcdgcd 的函数叫 __gcd 。upd:现在 NOIP 已经可以使用了。

  • 当积相同且 \gcdgcd 相同时,\operatorname{lcm}lcm 也一定相同,因此只需判断是否满足一、二两个条件即可。

  -------------------------------------------------------------------------------------------------------------------------------

C++源码:

#include<iostream>
using namespace std;
int ans=0;//ans是情况数量。 
int d(int a,int b){//求最大公约数函数。a,b是两个待求最大公约数的数,不是题里的x0y0。 
	if(a<b) swap(a,b);//确保a>b,为下一步除法做准备
	if(a%b==0) return b;//如果a/b余0,那么b就是最大公约数。比如10和5, 10/5余0,5就是最大公约数 
	else return d(b,a%b);//辗转相除法求最大公因数(其实交换ab那一步没必要,小除以大余小本身,到这里自然就换过来了,比如3和15,3/15余3,到这里就变成了15和3,嗯) 
}
int x(int a,int b){//最小公倍数 
	return (a*b/d(a,b));//最大公因数和最小公倍数的乘积等于原两个数的乘积。所以这两个数的乘积除以最大公因数等于最小公倍数。 
}
int main(){
	int x0,y0;//这才是x0y0. 
	cin>>x0>>y0;//(这里用个搜索就行了) 
	for(int i=x0;i<=y0;i++){//a一定在它的最大公因数和最小公倍数之间,这很明显 
		int j=x0*y0/i;//最大公因数和最小公倍数的乘积等于原两个数的乘积。老道理 。b就这样算 
		if(d(i,j)==x0&&x(i,j)==y0)// 如果ab(ij)的最大公因数,最小公倍数符合x0y0 
			ans++;//计数 
	}
	cout<<ans<<endl;
	return 0;
}	

  -------------------------------------------------------------------------------------------------------------------------------

C++源码2:

#include <bits/stdc++.h>
using namespace std;
long long x,y;
inline long long gcd(long long x,long long y)
{
	if(y==0) return x;
	return gcd(y,x%y);
}
int main()
{
	cin>>x>>y;
	long long ans=0;
	for(long long i=1;i<=sqrt(x*y);i++)
	{
		if(x*y%i==0&&gcd(i,x*y/i)==x) ans++;
	}
	ans*=2;
  	if(x==y) ans--;
   	cout<<ans;
	return 0;
}

  -------------------------------------------------------------------------------------------------------------------------------

C++源码3:

#include <iostream>
int main()
{
    int x, y;
    std::cin >> x >> y;
    if (y % x != 0)
        std::cout << 0;
    else
    {
        int quotient = y / x;
        int count = 0;        //统计素因数的个数
        int currentFactor = 2; //用来试验整除性的因数
        while (quotient > 1) //等于1时标志着分解完毕
        {
            if (quotient % currentFactor == 0)
            {
                count++;
                while (quotient % currentFactor == 0)
                    quotient /= currentFactor;//若能整除就除到底
            }
            currentFactor++;
        }
        std::cout << (1 << count);//使用位运算来产生2的方幂
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/djfihhfs/article/details/128454881