【洛谷 1072 & 藍橋杯 算法訓練 ALGO - 37】Hankson的趣味題


題目鏈接:http://lx.lanqiao.cn/problem.page?gpid=T99

1 題目

題目描述

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 的個數。請你幫助他編程求解這個問題。

輸入格式

輸入第一行爲一個正整數n,表示有n 組輸入數據。
接下來的n 行每 行一組輸入數據,爲四個正整數a0,a1,b0,b1,每兩個整數之間用一個空格隔開。輸入 數據保證a0 能被a1 整除,b1 能被b0 整除。

輸出格式

輸出共n 行。每組輸入數據的輸出結果佔一行,爲一個整數。
對於每組數據:若不存在這樣的 x,請輸出0; 若存在這樣的 x,請輸出滿足條件的x 的個數;

樣例輸入

2
41 1 96 288
95 1 37 1776

樣例輸出

6
2

樣例說明

第一組輸入數據,x 可以是9、18、36、72、144、288,共有6 個。
第二組輸入數據,x 可以是48、1776,共有2 個。

2 分析

首先,直接暴力枚舉只能過 50%50\% 的數據。

1.關於兩個定理:

  • 最大公約數
int gcd(int a, int b){   
    return b == 0 ? a : gcd(b, a % b);     
}
  • 最小公倍數
int lcm(int a, int b){
	return a * b / gcd(a, b);
}

2.一個結論:設 gcd(x,a0)=a1gcd(x,a_{0})=a_{1} ,並有
{x=k1a1a0=k2a1 \left\{ \begin{aligned} x=k_{1}*a_{1} \\ a_{0}=k_{2}*a_{1}& \end{aligned} \right.
gcd(k1,k2)=1gcd(k_{1},k_{2})=1

證明:

  • 假設 gcd(k1,k2)1gcd(k_{1},k_{2})\neq1gcd(k1,k2)=Kgcd(k_{1},k_{2})=K,並有
    {k1=pKk2=qK \left\{ \begin{aligned} k_{1}=p*K \\ k_{2}=q*K& \end{aligned} \right.
  • 由假設得:
    {x=pKa1a0=qKa1 \left\{ \begin{aligned} x=p*K*a_{1} \\ a_{0}=q*K*a_{1}& \end{aligned} \right.
  • 可得 gcd(x,a0)=Ka1a1gcd(x,a_{0})=K*a_{1}\neq a_{1},結果與題目條件不符,假設不成立
  • gcd(k1,k2)=1gcd(k_{1},k_{2})=1

因此可得:

對於兩個正整數 a,ba,b ,設 gcd(a,b)=kgcd(a,b)=k 則存在 gcd(a/k,b/k)=1gcd(a/k,b/k)=1

3.推導

  • 由最大公約數定理
    gcd(x,a0)=a1 gcd(x,a_{0})=a_{1}

    gcd(xa1,a0a1)=1 gcd(\frac {x} {a_{1}} ,\frac {a_{0}}{a_{1}})=1
  • 由最小公倍數定理
    lcm(x,b0)=b1=xb0gcd(x,b0) lcm(x,b_{0})=b_{1}=\frac {x*b_{0}}{gcd(x,b_{0})}

    gcd(x,b0)=xb0b1 gcd(x,b_{0})=\frac{x*b_{0}}{b_{1}}

    gcd(b1b0,b1x)=1 gcd(\frac {b_1} {b_{0}} ,\frac {b_{1}}{x})=1

4.最終可得如下結論:
{gcd(xa1,a0a1)=1gcd(b1b0,b1x)=1 \left\{ \begin{aligned} gcd(\frac {x} {a_{1}} ,\frac {a_{0}}{a_{1}})=1 \\ gcd(\frac {b_1} {b_{0}} ,\frac {b_{1}}{x})=1& \end{aligned} \right.

3 題解

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

int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a % b);
}

int main(){
	int n;
	cin >> n;
	while(n--){
		int a0, a1, b0, b1, ans = 0;
		cin >> a0 >> a1 >> b0 >> b1;
		for(int x = 1;x <= sqrt(b1);x++){
			if(b1 % x == 0){
				if(x % a1 == 0 && gcd(x / a1, a0 / a1) == 1 && gcd(b1 / x, b1 / b0) == 1){
					ans++;
				}
				//枚舉另一個因子 
				int y = b1 / x;
				if(y == x){
					continue;
				}
				if(y % a1 == 0 && gcd(y / a1, a0 / a1) == 1 && gcd(b1 / y, b1 / b0) == 1){
					ans++;
				}
			}
		}
		if(ans != 0){
			printf("%d\n", ans);
		}else{
			printf("0\n");
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章