欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
因为 lcm ( x , b 0 ) = b 1 \operatorname{lcm}(x,b_0)=b_1 lcm(x,b0)=b1,所以 x x x是 b 1 b_1 b1的因数,所以 x x x的质因子一定也是时 b 1 b_1 b1的质因子。我们可以对 b 1 b_1 b1的每个质因子p,计算 x x x可能包含多少个 p p p。
设 a 0 , b 0 , a 1 , b 1 , x a_0,b_0,a_1,b_1,x a0,b0,a1,b1,x分别包含 m a , m b , m c , m d , m x m_a,m_b,m_c,m_d,m_x ma,mb,mc,md,mx个质因子 p p p,其中 m x m_x mx是未知数。
根据最大公约数的定义,在 gcd ( a 0 , x ) = a 1 \gcd(a_0,x)=a_1 gcd(a0,x)=a1中:
- 若 m a > m c m_a>m_c ma>mc,则 m x = m c m_x=m_c mx=mc
- 若 m a < m c m_a<m_c ma<mc,则无解
- 若 m a = m c m_a=m_c ma=mc,则 m x ≥ m c m_x\ge m_c mx≥mc即可
同理,根据最小公倍数的定义,在 lcm ( b 0 , x ) = b 1 \operatorname{lcm}(b_0,x)=b_1 lcm(b0,x)=b1中
- 若 m b < m d m_b<m_d mb<md,则 m x = m d m_x=m_d mx=md.
- 若 m b > m d m_b>m_d mb>md,则无解
- 若 m b = m d m_b=m_d mb=md,则 m x ≤ m d m_x\le m_d mx≤md即可 .
结合两种情况,有以下结论:
- 若 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 x = m c = m d m_x=m_c=m_d mx=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 c m_x=m_c mx=mc
- 若 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 d m_x=m_d mx=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_c mc~ m d m_d md之间的任意值,共有 m d − m c + 1 m_d-m_c+1 md−mc+1种取法。
- 其他情况, m x m_x mx 无解.
我们把
m
x
m_x
mx的取法数记为
c
n
t
p
cnt_p
cntp,也就是
x
x
x包含质因子
p
p
p的方案有
c
n
t
p
cnt_p
cntp种,根据乘法原理,根据题意的
x
x
x数量即为连乘积:
∏
质
数
p
∣
d
c
n
t
p
\prod _{质数p\mid d}cnt_p
质数p∣d∏cntp
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define ll long long
using namespace std;
const int N=45010;
const int inf=45000;
const int M=40000;
bool v[N];int prime[M],m;
inline void g_p()
{
m=0;memset(v,false,sizeof(v));
for(int i=2;i<=inf;i++)
{
if(!v[i])prime[++m]=i;
for(int j=1;j<=m&&i*prime[j]<=inf;j++)
{
v[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
int get(int &a,int b)
{
int ans=0;
while(a%b==0)a/=b,ans++;
return ans;
}
int a0,a1,b0,b1;
int calc(int x)
{
int ans=0;
int ma=get(a0,x),mb=get(b0,x),mc=get(a1,x),md=get(b1,x);
if(ma==mc&&mb==md&&mc<=md)ans=md-mc+1;
else if(ma>mc&&mb==md&&mc<=md)ans=1;
else if(ma==mc&&mb<md&&mc<=md)ans=1;
else if(ma>mc&&mb<md&&mc==md)ans=1;
return ans;
}
int main()
{
g_p();
int n;scanf("%d",&n);
while(n--)
{
int ans=1;
scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
for(int i=1;i<=m&&(ll)prime[i]*prime[i]<=b1;i++)
{
if(b1%prime[i]==0)
ans*=calc(prime[i]);
}
if(b1>1)ans*=calc(b1);
printf("%d\n",ans);
}
return 0;
}