Hankson的趣味题(NOIP2009)

题目链接:Hankson的趣味题
怎么讲呢?感觉这一题的难度给高了。
其实涉及的数学推理其实并不难,而且一旦数学推理结束,就是暴力枚举了,而且代码也短没什么难度。
所以我们就进行一下关键的数学分析。
我们要求x满足一下要求:

  1. (x,a0)=a1
  2. [x,b0]=b1

括号是什么意思,大家应该知道。
我们不妨设:

  • x=m*a1
  • a0=a*a1
  • b1=n*x
  • b1=b*b0

其中,m、a、n、b均为正整数。
分析条件1,可以得到(a,m)=1
分析条件2,可以得到(n,b)=1
再由我们设的式子可以得到:b1=m*n*a1
所以我们只要枚举m(因为m*n=b1/a1是一个定值),即可确定有多少个x。
因为x显然由m和n唯一确定,也就是两者一一对应(对应原理)
由m和n的乘积,我们知道b1/a1必须是个整数,所以我们可以判断一下,如果不是,直接输出0就行了。
接下来是枚举,由于数据比较大,我们可以采取每次枚举两对m和n,比如我们令up=b1/a1,枚举到i时,我们可以检验m=i、n=up/i和m=up/i、n=i,这样我们的i只需要枚举到i*i<=up即可,否则,如果你把i枚举到up,是会T的。
接下来,还要注意m==n的情况,不要重复计算。
所以,代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int a0,a1,b0,b1;
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
int main(){
    scanf("%d",&n);
    while(n--){
        int ans=0;
        scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
        int a=a0/a1,b=b1/b0;
        int up=b1/a1;
        double check=(double)b1/(double)a1;
        if(check!=(double)up){
            printf("0\n");
            continue;
        }
        for(int i=1;i*i<=up;i++){
            if(up%i==0){
                if((gcd(a,i)==1)&&(gcd(b,up/i)==1)){
                    ans++;
                }
                if((gcd(a,up/i)==1)&&(gcd(b,i)==1)){
                    if(i!=up/i){
                        ans++;
                    }

                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cggwz/article/details/81073152