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


京公网安备 11010502036488号