[洛谷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\n",ans);
	}
	return 0;
}
posted @ 2020-07-19 16:03  HH_Halo  阅读(192)  评论(0编辑  收藏  举报