问题描述
小Hi最近在追求一名学数学的女生小Z。小Z其实是想拒绝他的,但是找不到好的说辞,于是提出了这样的要求:对于给定的两个正整数N和M,小Hi随机选取一个N的约数N',小Z随机选取一个M的约数M',如果N'和M'相等,她就答应小Hi。小Z让小Hi去编写这个随机程序,到时候她review过没有问题了就可以抽签了。但是小Hi写着写着,却越来越觉得机会渺茫。那么问题来了,小Hi能够追到小Z的几率是多少呢?
输入
每个输入文件仅包含单组测试数据。
每组测试数据的第一行为两个正整数N和M,意义如前文所述。
对于40%的数据,满足1<=N,M<=106
对于100%的数据,满足1<=N,M<=1012
输出
对于每组测试数据,输出两个互质的正整数A和B(以A分之B表示小Hi能够追到小Z的几率)。
样例输入
3 2
样例输出
4 1
思路
1)分别求出A,B的所有约数,然后求出公共的,再进行计算(看数据范围就知道这个会超时)
2)只求个数:分别求出A,B和他俩的最大公约数(辗转相除法,这个就不用说了)的约数个数,a1,a2,a3,然后计算a3/(a1*a2)就行了
这里就用到了约数个数定理:
设n=p1^k1*p2^k2*……*pn^kn,其中p1,p2,……,pn为互不相同的质数,k1,k2,……,kn为正整数(这叫n的标准分解)
则n所有正约数个数为(k1+1)(k2+2)*……*(kn+1)个
则n所有正约数个数为(k1+1)(k2+2)*……*(kn+1)个
例如:将378000分解质因数378000=2^4×3^3×5^3×7^1
由约数个数定理可知378000共有正约数(4+1)×(3+1)×(3+1)×(1+1)=160个。
由约数个数定理可知378000共有正约数(4+1)×(3+1)×(3+1)×(1+1)=160个。
ps:之前对这些不熟悉,后来发现还有约数和定理等等,大家有兴趣的可以去自己搜搜
代码
#include<iostream>
#include<math.h>
using namespace std;
typedef long long doubleLong;
doubleLong yueshu(doubleLong a,doubleLong b)
{
doubleLong temp;
while(a!=0){
temp=b%a;
b=a;
a=temp;
}
return b;
}
int geshu(doubleLong a)
{
int sum=1;
for(doubleLong i=2;i*i<=a;i++)
{
int n=0;
while(a%i==0)
{
a=a/i;
n++;
}
if(n!=0)
{
sum=sum*(n+1);
}
}
if(a!=1)
{
sum=sum*2;
}
if(sum==1)
{
if(a==1)
return 1;
else
return 2;
}
return sum;
}
int main()
{
doubleLong m,n,y;
cin>>m>>n;
if(m>n)
y=yueshu(m,n);
else
y=yueshu(n,m);
int ry=geshu(y);
int rm=geshu(m);
int rn=geshu(n);
int yy=yueshu(ry,rn*rm);
cout<<rm*rn/yy<<" "<<ry/yy<<endl;
return 0;
}