Noip2009 Hankson 的趣味题 (简单数学)

题意:n组询问,每组给定四个正整数a0,a1,b0,b1, 求满足gcd(x,a0) = a1, lcm(x,b0) = b1的x的个数。

输入格式:

第一行,一个正整数n;

第二行,四个正整数a0,a1,b0,b1;

输出格式:

共n行,每行一个正整数,表示满足条件的x的个数。

样例输入:

2
41 1 96 288
95 1 37 1776

样例输出:

6
2

解析:一道简单的数学题。先来看一个简单的定理,gcd(a,b) = c, 则gcd(a/c,b/c) = 1. 定理的正确性很显然,在本题中,要求gcd(x,a0) = a1,即是gcd(x/a1,a0/a1) = 1。又要求lcm(x,b0)=b1,而lcm(x,b0) = x*b0/gcd(x,b0), 所以gcd(x,b0) = x*b0/lcm(x,b0). 因为lcm(x,b0) = b1,所以gcd(x,b0) = x*b0/b1. 同理,gcd(x/(x*b0/b1),b0/(x*b0/b1)) = 1,化简可得gcd(b1/b0,b1/x) = 1. 推到了这里,我们得到了两个式子,即gcd(x/a1,a0/a1) = 1,gcd(b1/b0,b1/x) = 1。可以发现x为a1的倍数,并且为b1的因数。所以我们只需要枚举b1的每个因子,再进行判断便可,复杂度o(n√b1)。

代码如下:

#include<cstdio>
#include<cmath>
using namespace std;

int n,a0,a1,b0,b1,ans;

int read(void) {
    char c; while (c=getchar(),c<'0' || c>'9'); int x=c-'0';
    while (c=getchar(),c>='0' && c<='9') x=x*10+c-'0'; return x;
}

int gcd(int x,int y) {  //求gcd 
    if (y==0) return x; else return gcd(y,x%y);
}

int main() {
    n=read();
      while (n--) {
          ans=0;
          a0=read(); a1=read(); b0=read(); b1=read();
            for (int i=1;i<=sqrt(b1);++i) {  //枚举每个因数 
              if (!(b1%i)) {  //如果是i是b1的因数 
                if (gcd(b1/b0,b1/i)==1 && i%a1==0 && gcd(i/a1,a0/a1)==1) ans++;
                if (i==b1/i) continue;  //如果因数i与b1/i相等,就continue,防止重复计算 
                if (gcd(b1/b0,i)==1 && (b1/i)%a1==0 && gcd(b1/i/a1,a0/a1)==1) ans++;
              }
            }
          printf("%d
",ans);
      }
    return 0;
}
原文地址:https://www.cnblogs.com/Gaxc/p/9526289.html