分析:b1肯定是在a0,a1,b0,b1三个数中最大的,因为b1是b0最小公倍数,a1是a0最大公约数,b1含有所有的质因子交集,因此我们可以枚举所有b1的约数,查看有多少个满足条件的x。
如果用试除法求出b1的所有约数的话,时间复杂度是O(10^8)
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=50005;
typedef long long ll;
typedef pair<int,int> PII;
PII f[N];
int d[N];
int fcnt,dcnt;
void divide(int x)
{
for(int i=2;i<=x/i;i++)
if(x%i==0)
{
int s=0;
while(x%i==0) x/=i,s++;
f[fcnt++]={i,s};
}
if(x>1) f[fcnt++]={x,1};
}
void dfs(int now,int t)
{
if(now>=fcnt)
{
d[dcnt++]=t;
return;
}
int p=f[now].first,s=f[now].second;
for(int i=0;i<=s;i++)
{
dfs(now+1,t);
t*=p;
}
}
int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
int main()
{
int n;
cin>>n;
while(n--)
{
memset(f,0,sizeof f);
memset(d,0,sizeof d);
int a0,a1,b0,b1;
cin>>a0>>a1>>b0>>b1;
dcnt=fcnt=0;
divide(b1);
dfs(0,1);
int res=0;
for(int i=0;i<dcnt;i++)
{
int x=d[i];
if(1ll*x*b0/gcd(x,b0)==b1&&gcd(x,a0)==a1)
res++;
}
cout<<res<<endl;
}
}
质因子筛法
优化了试除法枚举2~n的所有元素,而只是转过来只枚举质因子,并记录他们的指数,可以达到时间优化的效果
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=50005;
int primes[N];
int cnt,d[N];
bool st[N];
typedef pair<int,int> PII;
PII f[N];
int fcnt,dcnt;
void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]*i<=n;j++)
{
int t=primes[j]*i;
st[t]=true;
if(i%primes[j]==0) break;
}
}
}
void divide(int n)
{
for(int i=0;primes[i]<=n/primes[i];i++)
if(n%primes[i]==0)
{
int s=0;
int p=primes[i];
while(n%p==0) n/=p,s++;
f[fcnt++]={p,s};
}
if(n>1) f[fcnt++]={n,1};
}
void dfs(int now,int t)
{
if(now>=fcnt)
{
d[dcnt++]=t;
return ;
}
int p=f[now].first,s=f[now].second;
for(int i=0;i<=s;i++)
{
dfs(now+1,t);
t=t*p;
}
}
int gcd(int a,int b)
{
if(!b) return a;
return gcd(b,a%b);
}
int main()
{
int t;
cin>>t;
init(N-4);
while(t--)
{
memset(d,0,sizeof d),memset(f,0,sizeof f);
dcnt=fcnt=0;
int a0,a1,b0,b1;
cin>>a0>>a1>>b0>>b1;
divide(b1);
dfs(0,1);
int res=0;
for(int i=0;i<dcnt;i++)
{
int x=d[i];
if(gcd(a0,x)==a1&&1ll*b0*x/gcd(b0,x)==b1)
res++;
}
cout<<res<<endl;
}
return 0;
}