数学-洛谷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;//这样写我们就可以直接用intif(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互质即可。

posted @ 2017-03-31 20:02  largecube233  阅读(115)  评论(0编辑  收藏  举报