版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83063396
题意
求gcd(a0,x)=a1且lcm(b0,x)=b1中x的解的方案数。
题解
这种gcd的问题一般都要拆成质因数来分析。
线筛出1~sqrt(2e9)中的素数,那么所有数的质因数一定在其中出现,不然它本身就是一个素数(这个要特判)。
对于质数p,他们的次数分别为ca0,ca1,cb0,cb1。
分析gcd的特点,因为gcd(a0,x)=a1,所以有min(ca0,x)=ca1。具体情况如下:
1、ca0<ca1,无解
2、ca0=ca1,cx>=ca0
3、ca0>ca1,cx=ca1
同理分析lcm,因为lcm(b0,x)=b1,所以max(cb0,x)=cb1。具体分析:
1、cb0>cb1,无解
2、cb0=cb1,cx<cb0
3、cb0<cb1,cx=cb1
结合两者的情况,会有
1、ca0<cb0 或 cb0>cb1,无解
2、ca0=ca1 且 cb0=cb1,若同时有ca0<=cb0,则cx有cb0-ca0+1个取值方案
3、ca0=ca1 且 cb0<cb1,若同时有ca0<=cb1,则cx有1个取值方案
4、ca0>ca1 且 cb0=cb1,若同时有ca1<=cb0,则cx有1个取值方案
5、ca0>ca1 且 cb0<cb1,若同时有ca1=cb1,则cx有1个取值方案
好了,有了这些就可以打代码了,ans等于所有质因数中的取值方案累乘。
代码
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2010;
int tot=0,prime[40000];
int v[50000];
void getprime(int n)
{
for(int i=2;i<=n;i++)
{
if(v[i]==0)
{
v[i]=i;
prime[++tot]=i;
}
for(int j=1;j<=tot;j++)
{
if(prime[j]*i>n || v[i]<prime[j]) break;
v[prime[j]*i]=prime[j];
}
}
}
void get(int &x,int &cnt,int p)
{
while(x%p==0)
{
x/=p;cnt++;
}
}
int main()
{
getprime(sqrt(2e9)+10);
int T;
scanf("%d",&T);
while(T--)
{
int a0,a1,b0,b1;
scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
int ca0,ca1,cb0,cb1;
int ans=1,cnt;
for(int i=1;i<=tot;i++)
{
ca0=ca1=cb0=cb1=0;
get(a0,ca0,prime[i]);get(a1,ca1,prime[i]);
get(b0,cb0,prime[i]);get(b1,cb1,prime[i]);
if(ca0==ca1 && cb0==cb1 && ca0<=cb0) cnt=cb0-ca0+1;
else if(ca0==ca1 && cb0<cb1 && ca0<=cb1) cnt=1;
else if(ca0>ca1 && cb0==cb1 && ca1<=cb0) cnt=1;
else if(ca0>ca1 && cb0<cb1 && ca1==cb1) cnt=1;
else{ans=0;break;}
ans*=cnt;
}
if(ans!=0)//如果其本身不为1,说明其本身是素数
{
recheck: int p;
if(a0!=1){p=a0;goto begin;}
if(a1!=1){p=a1;;goto begin;}
if(b0!=1){p=b0;goto begin;}
if(b1!=1){p=b1;goto begin;}
goto end;
begin: ca0=ca1=cb0=cb1=0;
get(a0,ca0,p);get(a1,ca1,p);
get(b0,cb0,p);get(b1,cb1,p);
if(ca0==ca1 && cb0==cb1 && ca0<=cb0) cnt=cb0-ca0+1;
else if(ca0==ca1 && cb0<cb1 && ca0<=cb1) cnt=1;
else if(ca0>ca1 && cb0==cb1 && ca1<=cb0) cnt=1;
else if(ca0>ca1 && cb0<cb1 && ca1==cb1) cnt=1;
else{ans=0;break;}
ans*=cnt;
goto recheck;
}
// printf("(%lld %lld %lld %lld)\n",a0,a1,b0,b1);
end: printf("%d\n",ans);
}
return 0;
}