题意:传送门
题解:本题让求
g
c
d
(
a
,
x
)
=
c
并
且
l
c
m
(
b
,
x
)
=
d
的
x
的
个
数
gcd(a,x)=c并且lcm(b,x)=d的x的个数
gcd(a,x)=c并且lcm(b,x)=d的x的个数,首先可以知道的
x
x
x一定是
d
d
d的约数,于是使用朴素算法的话,用试除法求出
d
d
d的所有约数,再判断下其余的两个条件,复杂度为
d
+
2
∗
l
o
g
(
d
)
\sqrt{d}+2*log(d)
d+2∗log(d),总复杂度为
n
∗
d
≈
1
e
8
n*\sqrt{d}\approx1e8
n∗d≈1e8会超时,但是洛谷测试数据弱了,弱归弱,依旧要求正解不是,有个大概的公理需要了解下:
d的约数个数上限大约是√d,但是1~d中平均每个数的约数个数大约只有log(d)个。根据实际测试,10e9之内的自然数中,约数个数最多的自然数仅有1536个。
然后就是考虑如何快速求出一个数所有的约数呢?同时还有一个定理需要知道:
任何一个合数n必定包含一个不超过√n的质因子
所以先预处理处
1
∼
2
∗
1
0
9
1\sim\sqrt{2*10^9}
1∼2∗109的所有质数,然后进行质因数分解,最后搜索出所有的约数,复杂度为
O
(
2
∗
1
0
9
+
l
o
g
(
d
)
O(\sqrt{2*10^9}+log(d)
O(2∗109+log(d)。之后直接再判断其余两个条件即可。
最后总的复杂度为:
O
(
2
∗
1
0
9
+
n
∗
√
d
/
l
o
g
(
d
)
+
l
o
g
(
d
)
∗
l
o
g
2
(
d
)
O(\sqrt{2*10^9}+n*√d/log(d)+log(d)*log^2(d)
O(2∗109+n∗√d/log(d)+log(d)∗log2(d)
c
o
d
e
:
code:
code:
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=45000;
const int M=15;
int primes[N],cnt;
bool st[N];
pii factor[M];
int cntf;
int divider[N],cntd;
int n,a0,a1,b0,b1;
void get_primes(int n)
{
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;j<cnt&&primes[j]*i<=n;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
void dfs(int u,int p)
{
if(u>cntf){
divider[cntd++]=p;
return;
}
for(int i=0;i<=factor[u].second;i++){
dfs(u+1,p);
p*=factor[u].first;
}
}
int main()
{
get_primes(50000);
n=read();
while(n--){
a0=read();a1=read();b0=read();b1=read();
int d=b1;
cntf=0;
for(int i=0;primes[i]<=d/primes[i];i++){
int p=primes[i];
if(d%p==0){
int s=0;
while(d%p==0)s++,d/=p;
factor[++cntf]={p,s};
}
}
if(d>1)factor[++cntf]={d,1};
cntd=0;
dfs(1,1);
int res=0;
for(int i=0;i<cntd;i++){
int x=divider[i];
if(gcd(x,a0)==a1&&(ll)x*b0/gcd(x,b0)==b1){
res++;
}
}
printf("%d\n",res);
}
return 0;
}
还有另外一种做法,是这样的,对于
g
c
d
(
a
,
b
)
=
c
gcd(a,b)=c
gcd(a,b)=c而言
a
=
p
0
a
0
∗
p
1
a
1
∗
p
2
a
2
∗
⋯
∗
p
n
a
n
a=p_0^{a0}*p_1^{a1}*p_2^{a2}*\cdots*p_n^{an}
a=p0a0∗p1a1∗p2a2∗⋯∗pnan
b
=
p
0
b
0
∗
p
1
b
1
∗
p
2
b
2
∗
⋯
∗
p
n
b
n
b=p_0^{b0}*p_1^{b1}*p_2^{b2}*\cdots*p_n^{bn}
b=p0b0∗p1b1∗p2b2∗⋯∗pnbn
c
=
p
0
m
i
n
(
a
0
,
b
0
)
∗
p
1
m
i
n
(
a
1
,
b
1
)
∗
⋯
∗
p
n
m
i
n
(
a
n
,
b
n
)
c=p_0^{min(a0,b0)}*p_1^{min(a1,b1)}*\cdots*p_n^{min(an,bn)}
c=p0min(a0,b0)∗p1min(a1,b1)∗⋯∗pnmin(an,bn)
而对于lcm(a,b)而言
a
=
p
0
a
0
∗
p
1
a
1
∗
p
2
a
2
∗
⋯
∗
p
n
a
n
a=p_0^{a0}*p_1^{a1}*p_2^{a2}*\cdots*p_n^{an}
a=p0a0∗p1a1∗p2a2∗⋯∗pnan
b
=
p
0
b
0
∗
p
1
b
1
∗
p
2
b
2
∗
⋯
∗
p
n
b
n
b=p_0^{b0}*p_1^{b1}*p_2^{b2}*\cdots*p_n^{bn}
b=p0b0∗p1b1∗p2b2∗⋯∗pnbn
c
=
p
0
m
a
x
(
a
0
,
b
0
)
∗
p
1
m
a
x
(
a
1
,
b
1
)
∗
⋯
∗
p
n
m
a
x
(
a
n
,
b
n
)
c=p_0^{max(a0,b0)}*p_1^{max(a1,b1)}*\cdots*p_n^{max(an,bn)}
c=p0max(a0,b0)∗p1max(a1,b1)∗⋯∗pnmax(an,bn)
也就是说前面几步仍然按照上面做,先预处理处
1
∼
2
∗
1
0
9
1\sim\sqrt{2*10^9}
1∼2∗109的所有质数,然后对
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d几个数分别对每个质因子进行求指数
m
a
,
m
b
,
m
c
,
m
d
m_a,m_b,m_c,m_d
ma,mb,mc,md
根据上面的
g
c
d
gcd
gcd本质:
- 若 m a > m c m_a>m_c ma>mc,则 m x m_x mx只能等于 m c m_c mc
- 若 m a = m c m_a=m_c ma=mc,则 m x m_x mx只需满足 m x ≥ m c m_x \geq m_c mx≥mc即可
- 若 m a < m c m_a<m_c ma<mc,无解
同理,根据 l c m lcm lcm本质:
- 若 m b < m d m_b<m_d mb<md,则 m x m_x mx只能等于 m d m_d md
- 若 m a = m c m_a=m_c ma=mc,则 m x m_x mx只需满足 m x ≤ m d m_x \le m_d mx≤md即可
- 若 m a > m c m_a>m_c ma>mc,无解
总结一下,也就是说对于此时要分解的这个质因子
p
p
p而言吧,如果
m
a
<
m
c
∣
∣
m
a
>
m
c
m_a<m_c||m_a>m_c
ma<mc∣∣ma>mc无解,要么就是
m
a
>
m
c
&
&
m
b
<
m
d
&
&
m
c
=
=
m
d
m_a>m_c\&\&m_b<m_d\& \&m_c==m_d
ma>mc&&mb<md&&mc==md,那么答案不变,不满足无解,另外一种就是
m
a
=
=
m
c
&
&
m
b
=
=
m
d
&
&
m
c
≤
m
d
m_a==m_c\&\&m_b==m_d\&\&m_c\le m_d
ma==mc&&mb==md&&mc≤md,那么
m
x
m_x
mx可以取
m
c
∼
m
d
m_c\sim m_d
mc∼md之间的任何值,也就是将答案乘上
(
m
d
−
m
c
+
1
)
(m_d-m_c+1)
(md−mc+1),至于其余各种情况都是只能取一个值而已,也就不用多考虑了。
最后如果说是
a
,
b
,
c
,
d
a,b,c,d
a,b,c,d中有不是
1
1
1的,说明某个值有超过
(
d
)
\sqrt(d)
(d)的质因子,此时和上面的分析也是差不多的,同时还是得先判断是否有
a
<
c
∣
∣
b
>
a
a<c||b>a
a<c∣∣b>a的无解情况,如果说
c
!
=
1
c!=1
c!=1说明如果
a
!
=
c
∣
∣
c
!
=
d
a!=c||c!=d
a!=c∣∣c!=d都会导致无解,有解的情况在于
b
0
=
=
b
1
&
&
b
1
!
=
1
b0==b1\&\&b1!=1
b0==b1&&b1!=1时,还会再多乘上
2
2
2
c
o
d
e
:
code:
code:
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int N=5e4+5;
int primes[N],cnt;
bool st[N];
void get_primes(int n)
{
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;j<cnt&&primes[j]*i<=n;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
int n,a0,a1,b0,b1;
pii factor[N],cntf;
int main()
{
get_primes(50000);
n=read();
while(n--){
a0=read();a1=read();b0=read();b1=read();
int ans=1;
bool flag=true;
for(int i=0;i<cnt;i++){
if(a0==1&&a1==1&&b0==1&&b1==1)break;
int p=primes[i];
int ma=0,mc=0,mb=0,md=0;
while(a0%p==0){
a0/=p;
ma++;
}
while(a1%p==0){
a1/=p;
mc++;
}
while(b0%p==0){
b0/=p;
mb++;
}
while(b1%p==0){
b1/=p;
md++;
}
if(ma<mc||mb>md){
flag=false;
break;
}
if(ma>mc&&mb<md){
if(mc!=md){
flag=false;
break;
}
}else if(ma==mc&&mb==md){
if(mc<=md){
ans*=(md-mc+1);
}else{
flag=0;
break;
}
}
}
if(!(a0==1&&a1==1&&b0==1&&b1==1)){
if(a1>a0||b0>b1)flag=0;
if(a1!=1&&a1!=b1&&a1!=a0)flag=0;
if(b1==b0&&b1!=1)ans<<=1;
}
if(!flag)ans=0;
printf("%d\n",ans);
}
return 0;
}