题意:传送门
题解:本题让求 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;
}