先预处理出$sqrt{2 imes {10}^9}$内的质数。
对于每个质数p,设a0,a1,b0,b1,x含p因子的个数分别为ma0,ma1,mb0,mb1,mx。
$1. qquad ecause gcd(x,a0)=a1,$
$qquad herefore$有以下情况:
(1)当$ma0<ma1$时,不符合最大公约数,x无解;
(2)当$ma0=ma1$时,$mx ge ma1$;
(3)当$ma0>ma1$时,$mx=ma1$,若小于则不满足,若大于,最大公约数可以更大。
$2. qquadecause lcm(x,b0)=b1,$
$qquad herefore$有以下情况:
(1)当$mb0>mb1$时,不符合最小公倍数,x无解;
(2)当$mb0=mb1$时,$mx le mb1$;
(3)当$mb0<mb1$时,$mx=mb1$,否则最小公倍数可以更小。
综合以上情况,当存在1.(1)或2.(1)的任意一个情况时,x无解;
有解的情况:
(1)当$ma0=ma1$且$mb0=mb1$时,若$ma1le mb1$,则$ma1 le mx le mb1$,有$mb1-ma1$个解;
(2)当$ma0=ma1$且$mb0<mb1$时,若$ma1le mb1$,则$mx=ma1 le mb1$,有一解;
(3)当$ma0>ma1$且$mb0=mb1$时,若$ma1le mb1$,则$mx=ma1 le mb1$,有一解;
(4)当$ma0>ma1$且$mb0<mb1$时,若$ma1=mb1$,则$mx=ma1=mb1$,有一解。
设因子p找到了$cnt_p$个解,
根据乘法原理,$ans=sum_{p|d(p>1)} cnt_p$
注意点:a0和b1可能很大,需要把它们当作p再计算;有些地方不要一直调试浪费时间,可以重打一遍,注意要注释原来的代码而不是删除。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int n,a0,a1,b0,b1;
int ma0,ma1,mb0,mb1;
int m,pri[25002],v[45002],ans;
void prime()
{
for(int i=2;i<=45000;i++)
{
if (!v[i]) pri[++m]=i;
for(int j=1;j<=m;j++)
{
if (i*pri[j]>45000) break;
v[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
void doit(int p)
{
ma0=ma1=mb0=mb1=0;
while(a0%p==0) {ma0++;a0=a0/p;}
while(a1%p==0) {ma1++;a1=a1/p;}
while(b0%p==0) {mb0++;b0=b0/p;}
while(b1%p==0) {mb1++;b1=b1/p;}
if (ma0<ma1||mb0>mb1) {ans=0;return;}
if (ma0==ma1&&mb0==mb1)
{
if (ma1<=mb1) ans*=(mb1-ma1)+1;
else ans=0;
return;
}
if ((ma0==ma1&&mb0<mb1)||(ma0>ma1&&mb0==mb1))
{
if (ma1<=mb1) ans*=1;
else ans=0;
return;
}
if (ma0>ma1&&mb0<mb1)
{
if (ma1==mb1) ans*=1;
else ans=0;
return;
}
}
int main()
{
prime();
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
ans=1;
for(int j=1;j<=m;j++)
doit(pri[j]);
if (a0>1) doit(a0);
if (b1!=a0&&b1>1) doit(b1);
printf("%d
",ans);
}
return 0;
}