这是在洛谷刷到的一个题,我觉得初学者可以试试这个题,现在我想说一下我的思路。这个我们要对于最大公约数与最小公倍数有一定的了解。之前了解一下最大公约数的求法,就是我们所说的辗转相除法。先介绍一下辗转相除法吧:就以其中一个测试用例为例,求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;
}
如果还有问题欢迎留言询问。