这道题好久就想做了,但是拖了好久好久。。。
这道题主要有两种做法吧;
分割线
第一种,大神的做法,我直接从大神那里拿过来了,可能侵权了。。。
gcd(x,a0)=a1gcd(x,a0)=a1
⇒{x=k1∗a1a0=k2∗a1⇒{x=k1∗a1a0=k2∗a1
⇒gcd(k1,k2)=1⇒gcd(k1,k2)=1
简单证明:
假设 gcd(k1,k2)≠1gcd(k1,k2)≠1
设 K=gcd(k1,k2)(K≠1)K=gcd(k1,k2)(K≠1)
⇒{k1=p∗Kk2=q∗K⇒{k1=p∗Kk2=q∗K
⇒{x=p∗K∗a1a0=q∗K∗a1⇒{x=p∗K∗a1a0=q∗K∗a1
⇒gcd(x,a0)=K∗a1≠a1⇒gcd(x,a0)=K∗a1≠a1
这个结论与题目条件不符,所以 gcd(k1,k2)=1gcd(k1,k2)=1成立
结合开始的式子,化简,得到 gcd(x/a1,a0/a1)=1gcd(x/a1,a0/a1)=1
把这个结论推广一下,得到结论 PP
对于两个正整数a,ba,b,设 gcd(a,b)=kgcd(a,b)=k,则存在gcd(a/k,b/k)=1gcd(a/k,b/k)=1
2.lcm
lcm(x,b0)=b1lcm(x,b0)=b1
⇒gcd(x,b0)=x∗b0/lcm(x,b0)=x∗b0/b1⇒gcd(x,b0)=x∗b0/lcm(x,b0)=x∗b0/b1
由结论PP得
gcd(x/(x∗b0/b1),b0/(x∗b0/b1))=1gcd(x/(x∗b0/b1),b0/(x∗b0/b1))=1
化简得
gcd(b1/b0,b1/x)=1gcd(b1/b0,b1/x)=1
3.gcd&&lcm
整理一下得到的重要的式子
{gcd(x/a1,a0/a1)=1gcd(b1/b0,b1/x)=1{gcd(x/a1,a0/a1)=1gcd(b1/b0,b1/x)=1
用心体会这两个式子,发现 xx 是 a1a1的整数倍且是 b1b1 的因子
这个好像由 gcd 和 lcm 也可以得到?嗯,就这样。
于是得到了一种解题思路
b√1b1 枚举 b1b1 的因子(也就是 xx ),如果这个数是 a1a1 的整数倍,并且满足那两个式子,ans++
简单一点儿说其实就是推导出一个式子,然后枚举,可惜我太弱哦了,竟然想不出来!!!
#include<cstdio>
using namespace std;
int gcd(int a,int b) {
return b==0?a:gcd(b,a%b);
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
int a0,a1,b0,b1;
scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
int p=a0/a1,q=b1/b0,ans=0;
for(int x=1;x*x<=b1;x++)
if(b1%x==0){
if(x%a1==0&&gcd(x/a1,p)==1&&gcd(q,b1/x)==1) ans++;
int y=b1/x;//得到另一个因子
if(x==y) continue;
if(y%a1==0&&gcd(y/a1,p)==1&&gcd(q,b1/y)==1) ans++;
}
printf("%d\n",ans);
}
return 0;
}
代码极其简洁而且有力!!!
第二种则是清北听神牛们讲过,不过有些细节要注意而已
就是对于每一个数进行质因数分解。
a=2^n1*3^n2*5^n3……
x=2^m1*3^m2……
由于gcd(a,b)=2^min(n1,m1)*……
所以我们可以直接进行一波大大大大模拟!!!
数据范围是2000000000,这里面不超过sqrt(n)个小于sqrt(n)的质数,和一个大于sqrt(n)的(这个数就是分解完剩下的那个)。
线性筛求出50000所有的质数,分解即可;
最后一个可以特殊一波!!!
附上我极其丑陋的代码!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=55000;
int vis[55000],p[6500];
int k=0;
void prim(){
memset(vis,0,sizeof(vis));
vis[0]=vis[1]=1;
for(int i=2;i<=inf;i++){
if(!vis[i]) p[++k]=i;
for(int j=1;j<=k&&i*p[j]<inf;j++){
vis[p[j]*i]=1;
if(!(i%p[j])) break;
}
}
}
typedef long long ll;
ll ans=1;
int main(){
prim();
int n;
cin>>n;
for(int i=1;i<=n;i++){
ans=1;
int a0,a1,b0,b1;
cin>>a0>>a1>>b0>>b1;
for(int j=1;j<=k;j++){
ll numa0=0,numa1=0,numb1=0,numb0=0;
if(a0==1&&a1==1&&b0==1&&b1==1) break;
while(a0%p[j]==0){numa0++;a0/=p[j];}
while(b0%p[j]==0){numb0++;b0/=p[j];}
while(a1%p[j]==0){numa1++;a1/=p[j];}
while(b1%p[j]==0){numb1++;b1/=p[j];}
if(numa1>numa0||numb1<numb0){
ans=0;
break;
}
if(numa0==numa1&&numb0==numb1){
if(numb0<numa0){
ans=0;break;
}else ans*=(numb1-numa1+1);
}
if(numa0<numa1||numb0>numb1) ans=0;
if(numa0>numa1&&numb0<numb1&&numa1!=numb1) ans=0;
}
if(b1>1){
ll sss=b1;
ll numa0=0,numa1=0,numb1=0,numb0=0;
//if(a0==1&&a1==1&&b0==1&&b1==1) break;
while(a0%sss==0){numa0++;a0/=sss;}
while(b0%sss==0){numb0++;b0/=sss;}
while(a1%sss==0){numa1++;a1/=sss;}
while(b1%sss==0){numb1++;b1/=sss;}
if(numa1>numa0||numb1<numb0){
ans=0;
}
if(numa0==numa1&&numb0==numb1){
if(numb0<numa0){
ans=0;
}else ans*=(numb1-numa1+1);
}
if(numa0<numa1||numb0>numb1) ans=0;
if(numa0>numa1&&numb0<numb1&&numa1!=numb1) ans=0;
}
cout<<ans<<endl;
}
}