[洛谷P1072]Hankson 的趣味題「數論」
阿新 • • 發佈:2020-07-19
[洛谷P1072]Hankson 的趣味題「數論」
題目描述
Hanks 博士是 BT(Bio-Tech,生物技術) 領域的知名專家,他的兒子名叫 Hankson。現在,剛剛放學回家的 Hankson 正在思考一個有趣的問題。
今天在課堂上,老師講解了如何求兩個正整數 \(c_{1}\) 和 \(c_{2}\) 的最大公約數和最小公倍數。現在 Hankson 認為自己已經熟練地掌握了這些知識,他開始思考一個“求公約數”和“求公倍數”之類問題的“逆問題”,這個問題是這樣的:已知正整數\(a_{0}\),\(a_{1}\),\(b_{0}\),\(b_{1}\) 設某未知正整數 \(x\) 滿足:
1. \(x\)
2. \(x\) 和 \(b_{0}\) 的最小公倍數是 \(b_{1}\)。
Hankson 的“逆問題”就是求出滿足條件的正整數 \(x\)。但稍加思索之後,他發現這樣的 \(x\) 並不唯一,甚至可能不存在。因此他轉而開始考慮如何求解滿足條件的 \(x\) 的個數。請你幫助他程式設計求解這個問題。
輸入格式
第一行為一個正整數 \(n\),表示有 \(n\) 組輸入資料。接下來的\(n\) 行每行一組輸入資料,為四個正整數 \(a_{0}\),\(a_{1}\),\(b_{0}\),\(b_{1}\),每兩個整數之間用一個空格隔開。輸入資料保證 \(a_{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;
}