想了一天才打出来,真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; }*/