想了一天才打出来,真TND离谱
容易发现lcm(b1,b0)=b1;
所以一个想法是基于b1,用删掉一些数的方法枚举x。
0.b=b1,ans=1;
1.首先判断一些非法的(一定为0的)组合,直接continue;
2.保留b中的因子a1,同时删去所有含a0/a1的质因子;
3.判断此时lcm(b,b0)是否还等于b1,不是直接continue;
4.枚举每个可能的质因数,统计一下a1,b,b0,b1四个数各含多少该质因数;
如果b0含的比b1小,无事发生;
如果b0含的和b1相同,那么ans*=[cnt(b1)-cnt(a1)+1];
不要忘记处理2.4.可能出现的最大的质因数即可。

编辑:追加极致优化版,洛谷最大数据15ms

/*时间复杂度O[n(logb+√b)]*/ 
#include<stdio.h>
int gcd(int a,int b){int x;while(b){x=a%b;a=b;b=x;}return a;}
int lcm(int a,int b) {return a / gcd(a,b) * b;}
int main()
{
    int n,a0,a1,b0,b1,ans,b;
    int i,k;
    scanf("%d",&n);
    while(n--)
    {
        ans=0;
        scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
        /*判断一些一定为0的情况*/ 
        if(a0%a1) {printf("0\n");continue;}
        if(gcd(b0,b1)!=b0) {printf("0\n");continue;}
        /*设b=b1,则lcm(b,b0)=b1,划重点:基于b寻找可能的x的个数。*/ 
        /*首先,gcd(x,a0)=a1说明x不能含有a0/a1中除1以外的因子,提前删去*/ 
        k=a0/a1;
        b=b1/a1;/*x中必须含有a1这个因子,一个质因子都不能少,所以要先删掉b中a0/a1的部分后再添回来*/
        for(i=2;i*i<=k;++i)
        {
            if(k%i==0)
            {
                while(k%i==0) k/=i;
                while(b%i==0) b/=i;
            }
        }
        if(k>1) while(b%k==0) b/=k; /*不要漏筛a0/a1中最大的质数*/ 
        b*=a1;/*回应上文*/ 
        if(lcm(b,b0)!=b1 ) {printf("0\n");continue;}/*如果删完了之后b不满足第二个式子了,那么肯定是0*/ 
        else
        {
            int a=a1;/*x中必须含有a1这个因子,一个质因子都不能少*/ 
            ans=1;
            for(i=2;i*i<=b1;++i)
            {
                if(b1%i==0)
                {
                    /*如果b0中某个质因子数少于b1,那么b必须与b1保持一致,对答案无贡献*/
                    /*如果b0中质因子个数等于b1,那么b就可以删掉一些该质因子*/
                    /*最少删剩a1中该质因子个数*/
                    /*对答案的贡献为:(cnt)b-(cnt)a+1,且与答案乘算*/ 
                    int cntb=0,cntb1=0,cnt=0,cnta=0;;
                    while(b0%i==0) b0/=i,++cntb;
                    while(b1%i==0) b1/=i,++cntb1;
                    while(b%i==0) b/=i,++cnt;
                    while(a%i==0) a/=i,++cnta;
                    if(cntb==cntb1) {ans=ans*(cnt-cnta+1);}
                }
            }
            if(b1>1)/*不要漏掉b1中最大的质因数*/ 
            {
                if(b1==b0 && b==b1 && a!=b) ans=ans*2;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
/*
#include<stdio.h>
int gcd(int a,int b){int x;while(b){x=a%b;a=b;b=x;}return a;}
int lcm(int a,int b) {return a / gcd(a,b) * b;}
int vis[45010],p[45010],cnt;
void Prime(){
    for(int i=2;i<=45000;i++)
    {
        if(!vis[i]) p[++cnt]=i;
        for(int j=1;j<=cnt&&i*p[j]<=45000;j++)
        {
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
} 
int main()
{
    Prime();
    int n,a0,a1,b0,b1,ans,flag;
    int i,k;
    int cnta0,cnta1,cntb0,cntb1;
    scanf("%d",&n);
    while(n--)
    {
        ans=flag=1;
        scanf("%d%d%d%d",&a0,&a1,&b0,&b1);

        if(a0%a1) {printf("0\n");continue;}
        if(gcd(b0,b1)!=b0) {printf("0\n");continue;}

        for(i=1,k=p[1];p[i]*p[i]<=b1;++i,k=p[i])
        {
            cnta0=0,cnta1=0,cntb0=0,cntb1=0;
            while(!(a0%k)) a0/=k,++cnta0;
            while(!(a1%k)) a1/=k,++cnta1;
            while(!(b0%k)) b0/=k,++cntb0;
            while(!(b1%k)) b1/=k,++cntb1;
            if(cnta0>cnta1)
                if(cntb1!=cntb0 && cntb1>cnta1) {printf("0\n");flag=0;break;}
                else continue;
            if(cntb1==cntb0)
                ans*=(cntb1-cnta1+1);
        }
        if(flag && b1>1)
        {
            cnta0=0,cnta1=0,cntb0=0,cntb1=1;
            if(!(a0%b1))++cnta0;
            if(!(a1%b1))++cnta1;
            if(!(b0%b1))++cntb0;
            if(cnta0>cnta1)
            {
                if(cntb1!=cntb0 && cntb1>cnta1) {printf("0\n");flag=0;break;}
            }
            else if(cntb1==cntb0)
                ans*=(cntb1-cnta1+1);
        }
        if(flag) printf("%d\n",ans);
    }
    return 0;
}*/