zoukankan      html  css  js  c++  java
  • [洛谷P1072]Hankson 的趣味题「数论」

    [洛谷P1072]Hankson 的趣味题「数论」

    题目描述

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

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

    1. (x)(a_{0}) 的最大公约数是 (a_{1})​;

    2. (x)(b_{0})​ 的最小公倍数是 (b_{1})

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

    输入格式

    第一行为一个正整数 (n),表示有 (n) 组输入数据。接下来的(n) 行每行一组输入数据,为四个正整数 (a_{0}),(a_{1}),(b_{0}),(b_{1}),每两个整数之间用一个空格隔开。输入数据保证 (a_{0})​ 能被 (a_{1}) 整除,(b_{1}) 能被 (b_{0}) 整除。

    输出格式

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

    对于每组数据:若不存在这样的 (x),请输出 (0),若存在这样的 (x),请输出满足条件的 (x) 的个数;

    输入输出样例

    输入 #1

    2 
    41 1 96 288 
    95 1 37 1776 
    

    输出 #1

    6 
    2
    

    思路分析

    • 复习数论时从虎歌博客上看到这道题,拿来做一做
    • 求最大公约数和最小公倍数而已,上去从(a_{1})暴力枚举,直接判断,显然超时,只拿了50分。
    • 这题是在素数的唯一分解定理下推荐的,这题竟然还和素数有关系???那就考虑用一下这个定理

    素数唯一分解定理:

    • 定义:任何一个大于 1 的正整数都能被唯一分解为有限个素数的乘积
      那么这题和这个定理到底有啥关系?
    • 本题应用:
      首先我们可以根据这个定理得出以下关系:
      (a_{1} = p_{1}*p_{2}*...*p_{x}*p_{y})
      根据题意:(gcd(x,a_{0})=a_{1})
      所以可以得出这样的关系:
      (x = p_{1}*p_{2}*p_{x}*p_{y}*...*p_{i}*p_{j} = a_{1}*...*p_{i}*p_{j})
      (a_{0} = p_{1}*p_{2}*p_{x}*p_{y}*...*p_{m}*p_{n} = a_{1}*...*p_{m}*p_{n})
      不难发现,(x)(a_{0})除与(a_{1})相同的部分素数以外,其余的各自的组成素数各不相同,即(x/a_{1})(a_{0}/a_{1})互质,得出(gcd(x/a_{1},a_{0}/a_{1})==1)
    • 推广结论:
      对于两个正整数(a,b),设(gcd(a,b)=k),则存在(gcd(a/k,b/k)=1)
    • 应用结论:
      根据(lcm(x,b_{0})=b_{1})得出(gcd(x,b_{0}) = x*b_{0}/b_{1})
      最后可推出以下两个式子
      (gcd(x/a_{1},a_{0}/a_{1})=1)
      (gcd(b_{1}/b_{0},b_{1}/x)=1)
      接下来我们只要枚举(b_{1})的因子,并且这个因子是(a_{1})的倍数,同时满足以上两式即可

    ps:挨个打数学符号是真滴麻烦

    代码

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read(){
       int s=0,w=1;
       char ch=getchar();
       while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
       while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
       return s*w;
    }
    
    int gcd(int x,int y){
    	return y==0? x : gcd(y,x%y);
    }
    int lcm(int x,int y){
    	return x*y/gcd(x,y);
    }
    int main(){
    	int n;n = read();
    	for(int i = 1;i <= n;i++){
    		int a,a1,b,b1;
    		a = read(),a1 = read(),b = read(),b1 = read();
    		int ans = 0;
    		for(int x=1;x*x<=b1;x++){//枚举到sqrt(b1)即可
            	if(b1%x==0){
                    if(x%a1==0&&gcd(x/a1,a/a1)==1&&gcd(b1/b,b1/x)==1) ans++; //满足条件
                    int y=b1/x;//同时得出另一个因子
                    if(x==y) continue; 
                    if(y%a1==0&&gcd(y/a1,a/a1)==1&&gcd(b1/b,b1/y)==1) ans++;
                }
            }
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Session服务器配置指南与使用经验
    string和byte[]的转换 (C#)
    错误1已授予对“SqlAccess...的友元访问解决方法
    网络视频会议 二
    Editplus配置环境变量
    TSC 条码打印机 Dll 说明
    源码C#事例网址
    C#中的日志类
    分页事例 比较好的
    dotnet 网络编程 tcp
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13340044.html
Copyright © 2011-2022 走看看