數論學習筆記 (3):因數與倍數

godmoo發表於2024-04-30

\(\texttt{godmoo}\text{ }\texttt{の}\text{ }\texttt{數論學習筆記 之}\text{ }\boxed{因數與倍數}\)

定義

  • 因數/約數,倍數:若 \(d \mid n\),則 \(d\)\(n\) 的因數,\(n\)\(d\) 的倍數。

  • 公因數/公約數,公倍數:公共的因數/約數、倍數。

  • 最大公因(約)數:\(GreatestCommonDivisor(gcd)\),最大的公因數,規定 \(gcd(0,a)=a\)

  • 最小公倍數:\(LeatestCommonMultiple(lcm)\),最小的公倍數。

\(eg.\text{ }gcd(24,18)=6,lcm(24,18)=72\)

性質

  • 唯一分解定理:任意大於 \(1\) 的整數都可以寫成有限個質數乘積的形式,即:
    \(n=\prod_{i=1}^m p_i^{c_i}\)
  • \(gcd\)\(lcm\) 的最值表示法:若有 \(x=\prod_{i=1}^m p_i^{a_i}\)\(y=\prod_{i=1}^m p_i^{b_i}\),則有:

\[gcd=\prod_{i=1}^m p_i^{min(a_i,b_i)} \]

\[lcm=\prod_{i=1}^m p_i^{max(a_i,b_i)} \]

正確性:由定義推出。

  • \(gcd\)\(lcm\) 的性質:\(x \times y=gcd \times lcm\)

正確性:由 \(gcd\)\(lcm\) 的最值表示法推出。

\(\bold{gcd}\) 求法

  • 分解質因數:分解後用 \(gcd\) 的最值表示法,\(O(\sqrt{n})\)
  • 歐幾里得演算法:又名輾轉相除法,\(gcd(a,b)=gcd(b,a\text{ }mod\text{ }b)\)

證明
\(g=gcd(a,b)\)
\(\large\text{Part1.}\) 證明是公因數
首先 \(g\)\(a\),\(b\) 的因數;
我們知道,\(a\text{ }mod\text{ }b=a-\lfloor\frac{a}{b}\rfloor b\)
那麼 \(g\) 也是這個式子的因數;
所以 \(g\)\(b\)\(a\text{ }mod \text{ }b\) 的公因數。
\(\large\text{Part2.}\) 證明是最大公因數
假設存在更大的公因數 \(k\)
\(k \mid b\)\(k \mid a-\lfloor\frac{a}{b}\rfloor b\)
於是 \(k \mid b\)\(k \mid a\)
此時,\(k\)\(a\)\(b\) 的公因數;
\(k \gt g\),與 \(g=gcd(a,b)\) 矛盾;
所以 \(g=gcd(b,a\text{ }mod\text{ }b)\)

ll gcd(ll x,ll y){
	if(!y) return x;
	return gcd(y,x%y);
}

也可以寫成:

ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
  • 更相減損術:\(gcd(a,b)=gcd(b,a-b)\)

證明:與輾轉相除法的類似,不證。

  • \(\bm{Stein}\) 演算法:

針對大資料時,取模運算的效能會很低,使得輾轉相除法的效率不佳;但更相減損術的效率又不高,每次只能減一此。於是,\(Stein\) 演算法橫空出世,它避免了取模運算,但實測下來,它在大資料下的表現略勝一籌。
思想\(Stein\) 演算法基於更相減損術,由於計算機是以 \(2\) 進位制儲存的,所以位運算的效率極高,所以考慮用位移運算最佳化更相減損術。
流程
\(Case\text{ }1:\)\(a,b\) 一奇一偶時,
偶數除以 \(2\),顯然不影響結果;
\(Case\text{ }2:\)\(a,b\) 都是偶數時,
答案為 \(2\text{ }gcd(\frac{a}{2},\frac{b}{2})\)
\(Case\text{ }3:\)\(a,b\) 都是奇數時,
無法最佳化,直接做更相減損術;
\(【性質】:\text{ }\)\(Case\text{ }3\) 後必為 \(Case\text{ }1\),效率得到保證。

ll stein(ll x,ll y){
	if(x<y) x^=y,y^=x,x^=y; // swap的黑科技
	if(!y) return x;
	if(!(x&1)&&!(y&1)) return stein(x>>1,y>>1)<<1;
	if(!(x&1)&&(y&1)) return stein(x>>1,y);
	if((x&1)&&!(y&1)) return stein(x,y>>1);
	return stein(y,x-y);
}

相關文章