这道题其实是NOI2001的一道真题 改编,第一是多组数据,第二是时间复杂度要求较高。
一,暴力
每组数据直接2层循环,第一层枚举P,第二层枚举Q,如果满足条件就ans++,最后输出ans即可。
这里虽然是暴力,但是用了一点优化:
1.求a,b最小公倍数时可以直接a * b / (a和b的最大公约数)
2.因为最小公倍数%最大公约数一定 == 0,不等于0说明一定不能当最小公倍数和最大公约数
代码:
#include<bits/stdc++.h>
long long a,b,ans,i,j,t;
long long f1(long long a,long long b)
{
return a % b == 0 ? b : f1(b,a % b);
}
int main()
{
while(~scanf("%lld%lld",&a,&b))
{
if(b % a)
{
printf("0\n");
continue;
}
ans = 0;
for(i = a; i <= b; i++)
{
for(int j = a;j <= b;j++)
{
t = f1(i,j);
if(a == t && b == ((i * j) / t)) ans++;
}
}
printf("%lld\n",ans);
}
return 0;
}
时间复杂度:O(logN * N^2 * 数据组数)
二 ,优化掉一层循环
根据a * b = (a与b的最大公约数) * (a与b的最小公倍数),我们可以只枚举P,那么Q=输入的2数的积 / P,这样,我们就可以省去一层循环。
时间复杂度:O(log N * N * 数据组数)
代码:
#include<bits/stdc++.h>
long long a,b,ans,i,j,t;
long long f1(long long a,long long b)
{
return a % b == 0 ? b : f1(b,a % b);
}
int main()
{
while(~scanf("%lld%lld",&a,&b))
{
if(b % a)
{
printf("0\n");
continue;
}
ans = 0;
for(i = a; i <= b; i++)
{
j = a * b / i;
t = f1(i,j);
if(a == t && b == ((i * j) / t)) ans++;
}
printf("%lld\n",ans);
}
return 0;
}
三,正解
#include<bits/stdc++.h>
long long a,b,ans,i,j,t;
int main()
{
while(~scanf("%lld%lld",&a,&b))
{
if(b % a)
{
printf("0\n");
continue;
}
ans = 0;
b /= a;
for(i = 2; i * i <= b; i++)
if(b % i == 0)
{
ans++;
while(b % i == 0) b /= i;
}
printf("%lld\n",1<<(ans + (b > 1)));
}
return 0;
}