数学-洛谷P1072 Hankson 的趣味题
https://daniu.luogu.org/problem/show?pid=1072
一开始想了一个暴力,感觉很好;
我们考虑lcm;
lcm(a,b)=a*b/gcd(a,b);
这个因为两个互质的数lcm是其乘积可得;
显然我们读入一个b,要求a;
那么a一定被lcm整除;
而且枚举a直接枚举sqrt(lcm)就可以了;
所以时间复杂度将近1e5*O(gcd);
但这样是过不掉的;
各种瞎优化;
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define Ll long long
using namespace std;
int x,y,X,Y,m,ans,n;
int gcd(int x,int y){//非递归迭代加深gcd
int temp=1,X,Y; //本以为会很快,结果好像一般般
while(1){
if(x<y)swap(x,y);
if(!y)return x*temp;
if(x&1)
if(y&1)X=y,Y=x-y;
else X=y/2,Y=x;
else
if(y&1)X=x/2,Y=y;
else X=x/2,Y=y/2,temp*=2;
x=X; y=Y;
}
}
int main()
{
scanf("%d",&m);
while(m--){
ans=0;
scanf("%d%d%d%d",&x,&y,&X,&Y);
int A=x/y,B=Y/X,C=sqrt(Y);//这个一定要放在外面
for(int i=1;i<=C;i++)
{
if(Y%i)continue;//这样写我们就可以直接用int了
if(i%y==0)if(gcd(A,i/y)==1)if(gcd(B,Y/i)==1)ans++;
n=Y/i;
if(n==i)continue;//为什么这样可以写
if(n%y==0)if(gcd(A,n/y)==1)if(gcd(B,Y/n)==1)ans++;
}//和gcd,lcm的定义及基本数学质知识有关
printf("%d\n",ans);
}
}
小证明(从洛谷题解里面抄的)
lcm(x,b0)=x*b0/gcd(x,b0)=b1
=> b1*gcd(x,b0)=x*b0
=> gcd(x,b0)=x*b0/b1
=> gcd(b1/b0,b1/x)=1
标算
设x=a1*a2;a0=a1*a3;x*b2=b1;b0*b3=b1;
则a1*a2*b2=b1
又a1是x和a0的最大公约数,所以a2和a3互质。
又b1是x和b0的最小公倍数,所以b2和b3互质。
所以a2和a0/a1,b2和b1/b0互质。
因为a1*a2*b2=b1
所以a2*b2=b1/a1
因此a2,b2是b1/a1的因子,只需枚举并且判断是否与a3,b3互质即可。