当前位置: 代码迷 >> 综合 >> [NOIP2001 普及组] 最大公约数和最小公倍数题解
  详细解决方案

[NOIP2001 普及组] 最大公约数和最小公倍数题解

热度:74   发布时间:2023-12-05 09:57:32.0

        这是在洛谷刷到的一个题,我觉得初学者可以试试这个题,现在我想说一下我的思路。这个我们要对于最大公约数与最小公倍数有一定的了解。之前了解一下最大公约数的求法,就是我们所说的辗转相除法。先介绍一下辗转相除法吧:就以其中一个测试用例为例,求15,12的最大公约数。

 这就是辗转相除法的大概。再来看一个例子:

假如需要求 1997 和 615 两个正整数的最大公约数,用辗转相除法,是这样进行的:

1997 / 615 = 3 (余 152)

615 / 152 = 4(余7)

152 / 7 = 21(余5)

7 / 5 = 1 (余2)

5 / 2 = 2 (余1)

2 / 1 = 2 (余0)

至此,最大公约数为1

 看完这两个例子,我们来仔细了解一下这个算法。

        辗转相除法求最大公约数,我们就先让两个数相除然后进行取余。由图得z=x%y。然后我们让x=y;y=z;z=x%y。当z=0是就是我们辗转相除的结束,此时最大公约数就是此时的y。

while(a%b!=0){z=x%y;x=y;y=z;}

这就是辗转相除法的循环实现。

        再来看一看辗转相除法的递归实现。首先递归出口我们设为x%y==0时,这样直接返回y即可。否则的话,我们把y交给x,把x%y交给y,进行递归。看上面的图解应该可以写出这个递归推导式。

int zhanzhuan(int x,int y){if(x%y==0){return y;}else{return zhanzhuan(y,x%y);}
}

这就是递归的实现。

        解决了最小公约数的问题,我们回到这个题。我们把这个问题分为两半处理,这样可以提高我们代码执行效率。因为四个答案是两个乘数的换位,所以,我们只需要寻找一半即可,在

x->sqrt(x*y)这个范围内,寻找即可。每次让x++,y就是输入两个数的积除以x(y需要是整数,否则此循环直接跳过即可,可以用逻辑运算实现这一步),然后我们只需要判断此时的xy是不是以最初的x为最小公约数即可,我们用函数递归处理得到最小公约数,与最初的x进行比较,只要相等我们让计数器++即可。

        最后还需注意x,y如果相等也就是x=y=sqrt(最初的x*y)。这个时候两个乘数反转时答案是一样的,我们需要在答案中剔除这个相同的值。

        最后上一下ac代码

#include <iostream>
#include <cstdio>
#include <cmath>using namespace std;long long int yueshu(int x,int y){if(x%y==0){return y;}else{return yueshu(y,x%y);}
}int main(){int x,y;cin>>x>>y;int t=x;int flag=0;long long int ret=x*y;int count=0;while(x<=(long long int)(sqrt(ret))){if(yueshu(x,ret/x)==t&&(ret)%x==0){count++;long long int m=x*x;if(m==ret){flag=1;}}x++;}cout<<count*2-flag;return 0;
}

如果还有问题欢迎留言询问。

  相关解决方案