zoukankan      html  css  js  c++  java
  • [NOIp 2009]Hankson的趣味题

    Description

    Hanks 博士是 BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫 Hankson。现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。

    今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数。现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数 a0,a1,b0,b1,设某未知正整数 x 满足:

    1. x 和 a0 的最大公约数是 a1;

    2. x 和 b0 的最小公倍数是 b1。

    Hankson 的“逆问题”就是求出满足条件的正整数 x。但稍加思索之后,他发现这样的x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x 的个数。请你帮助他编程求解这个问题。

    Input

    第一行为一个正整数 n,表示有 n 组输入数据。接下来的 n 行每行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证 a0 能被 a1 整除,b1 能被 b0 整除。

    Output

    共 n 行。每组输入数据的输出结果占一行,为一个整数。

    对于每组数据:若不存在这样的 x,请输出 0;

    若存在这样的 x,请输出满足条件的 x 的个数;

    Sample Input

    2 
    41 1 96 288 
    95 1 37 1776 

    Sample Output

    6 
    2

    HINT

    【说明】

    第一组输入数据,x 可以是 9、18、36、72、144、288,共有 6 个。

    第二组输入数据,x 可以是 48、1776,共有 2 个。

    【数据范围】

    对于 50%的数据,保证有 1≤a0,a1,b0,b1≤10000 且 n≤100。

    对于 100%的数据,保证有 1≤a0,a1,b0,b1≤2,000,000,000 且 n≤2000。

    题解(转载)

    ->原文地址<-
    这题可以从$b_0$和$b_1$下手,考虑$b_0$和$b_1$的质因子,如果$b_1$的某个质因子和$b_0$的某个质因子的出现次数相同,那么$x$就可以取任意个(不超过$b_1$)该质因子。
    如果$b_0$的质因子和$b_1$的质因子出现的不相同,那么x含有该因子的次数就确定了,可以直接乘起来。
    最后我们把不确定的质因子$dfs$枚举出现次数,然后暴力判断$gcd(x, a_0) = a_1$即可。

     1 //It is made by Awson on 2017.10.8
     2 #include <map>
     3 #include <set>
     4 #include <cmath>
     5 #include <ctime>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <cstdio>
    10 #include <string>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define LL long long
    16 #define Max(a, b) ((a) > (b) ? (a) : (b))
    17 #define Min(a, b) ((a) < (b) ? (a) : (b))
    18 using namespace std;
    19 const int N = 5e4;
    20 
    21 int prime[N+5], top;
    22 bool isprime[N+5];
    23 int a, b, c, d;
    24 int qa[N+5], qt[N+5];
    25 int ans, pos;
    26 
    27 void prepare() {
    28   memset(isprime, 1, sizeof(isprime));
    29   isprime[1] = 0;
    30   for (int i = 2; i <= N; i++) {
    31     if (isprime[i]) prime[++top] = i;
    32     for (int j = 1; j <= top && prime[j]*i <= N; j++) {
    33       isprime[prime[j]*i] = 0;
    34       if (!(i%prime[j])) break;
    35     }
    36   }
    37 }
    38 int quick_pow(int a, int b) {
    39   int sum = 1;
    40   while (b) {
    41     if (b&1) sum *= a;
    42     a *= a;
    43     b >>= 1;
    44   }
    45   return sum;
    46 }
    47 int gcd(int a, int b) {
    48   return b ? gcd(b, a%b) : a;
    49 }
    50 bool judge(int p, int lo) {
    51   int t = c, cnt = 0;
    52   while (t%p == 0) t /= p, cnt++;
    53   return cnt != lo;
    54 }
    55 void dfs(int cen, int sum) {
    56   if (cen == pos+1) {
    57     if (gcd(sum, a) == b) ans++;
    58     return;
    59   }
    60   dfs(cen+1, sum);
    61   for (int i = 1; i <= qt[cen]; i++)
    62     dfs(cen+1, sum *= qa[cen]);
    63 }
    64 void work() {
    65   scanf("%d%d%d%d", &a, &b, &c, &d);
    66   int t = d, sum = 1; pos = 0; ans = 0;
    67   for (int i = 1; i <= top && prime[i] <= t; i++) {
    68     int cnt = 0;
    69     while (t%prime[i] == 0) t/=prime[i], cnt++;
    70     if (judge(prime[i], cnt)) sum *= quick_pow(prime[i], cnt);
    71     else qa[++pos] = prime[i], qt[pos] = cnt;
    72   }
    73   if (t != 1) {
    74     if (judge(t, 1)) sum *= t;
    75     else qa[++pos] = t, qt[pos] = 1;
    76   }
    77   dfs(1, sum);
    78   printf("%d
    ", ans);
    79 }
    80 int main() {
    81   int t; scanf("%d", &t);
    82   prepare();
    83   while (t--) work();
    84   return 0;
    85 }
  • 相关阅读:
    打印九九乘法表
    PAT (Basic Level) Practice (中文) 1091 N-自守数 (15分)
    PAT (Basic Level) Practice (中文)1090 危险品装箱 (25分) (单身狗进阶版 使用map+ vector+数组标记)
    PAT (Basic Level) Practice (中文) 1088 三人行 (20分)
    PAT (Basic Level) Practice (中文) 1087 有多少不同的值 (20分)
    PAT (Basic Level) Practice (中文)1086 就不告诉你 (15分)
    PAT (Basic Level) Practice (中文) 1085 PAT单位排行 (25分) (map搜索+set排序+并列进行排行)
    PAT (Basic Level) Practice (中文) 1083 是否存在相等的差 (20分)
    PAT (Basic Level) Practice (中文) 1082 射击比赛 (20分)
    PAT (Basic Level) Practice (中文) 1081 检查密码 (15分)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7637956.html
Copyright © 2011-2022 走看看