
先言
本篇文章部分內容進行了相互穿插,請結合目錄食用 。 如有不便,望見諒。
模運算
顧名思義 , 在模意義下進行運算,滿足普通加法減法乘法運算 。
例如 \(a + b = c (mod \ \ p) => a\ \ mod \ \ p + b \ \ mod = c (mod \ \ p)\) 拿一個具體數字 , 即為
\(5 + 7 = 5 (mod \ \ 7) => 5 \ \mod \ \ 7 + 7 \ \ mod \ \ 7 = 5 + 0 = 5 (mod \ \ 7)\)
減法同樣如此,但是在減法進行計算的時候,有可能會變成負數,但我們盡量不想讓其變成負數,那我們可以轉化成這樣 $ ( (a - b )mod \ \ c + c )mod \ \ c$ 與 \((a - b) mod \ \ c\) 在模意義下是滿足相等的。
除法則是滿足不滿足的,只有當 \(p\) 為質數時, 才可以進行 。
快速冪
冪運算就是 \(a^b\) 這樣的運算 。快速冪就是將 \(a^b\) 轉化成 \((a ^{\frac{b}{2}} )^2\) ,從而達到快速計算,同時對 \(b\) 進行一下討論是否為奇數。
\(Code\) 模板
int quick_pow(int a , int b , int p) //a ^ b % p
{
int ret = 1 ;
while(b)
{
if(b & 1) ret = ret * a % p ; //指數為奇數 。
a = a * a % p ;
b >>= 1 ;
}
return ret ;
}
模板題 【\(Code\)】
略微推一下出來的模板題 【\(Code\)】
素數(質數)
定義就是只能夠被 \(1\) 或者他自身整除的數字 。
判定
\(1.\)判斷一下 $2 \to n - 1 $ 是否能為 \(n\) 的因子 ,復雜度 \(O(n)\)
n 一定能夠被分解成\(a \times b\) 我們假設 \(a < b\) 那么我們只需要枚舉 \(a\) 即可,因為如果 \(a\) 不滿足乘除 \(n\) ,那么也不會有其它數能乘除 \(n\) ,同時 可以顯然 \(a\) 的上界為 \(\sqrt n\)
\(2.\) 判斷一下 \(2 \to \sqrt n\) ,看一下能否為 \(n\) 的因子,復雜度 \(O(\sqrt n)\)
篩法
算術基本定理
\(x = \prod p_{i} ^ {c_i}\) \(p_i\) 是個質數 。對於任意的 \(x\in N\) 均滿足上述式子,也就是每個數,都能被分解成幾個質數和質數的平方的乘積 。
具體證明或者其他,詳見此博客
質數分布定理
\(1 \to n\) 的質數個數大約是: $ \frac{x}{\ln(x)}$ , 其數學中給出了詳細且嚴謹的證明,\(OI\) 就不必深究其證明了
\(1.\) 試除法篩素數 ,
原理:枚舉 \(1 \to n\) 這些所有的數, 同時,再用試除法 \(2\to \sqrt n\) 來判斷一下第 \(i\) 個數是否為素數 ,預計復雜度 \(O(n \times \sqrt n)\)
\(2.\) 埃氏篩
原理 : 就是由於素數的倍數必然不是一個質數,那么我們在枚舉到一個質數的時候,我們將它的所有倍數刪除掉,那么剩下的,就是質數了 , 復雜度 : \(O(n\times \log(\log n))\)
for(int i = 2 ; i <= n ; i++)
{
if(!vis[i])
{
prime[++tot] = i ;
for(int j = i ; j * i <= n ; j++)
{
vis[i * j] = 1 ;
}
}
}
\(3.\) 線性篩
原理和埃氏篩一致,都是刪去素數的倍數從而使得剩下便是質數,那么它是埃氏篩的進一步優化。也就是讓所有的數都只被訪問一遍。
實現:讓所有的數都只被訪問一遍,也就是只被輸出一遍,那么我們讓它只能被它的最小質因子訪問。
for(int i = 2 ; i <= n ; i++)
{
//不管 i 是否為質都要篩掉其它數字
//從小到大枚舉素數
for(int j = 0 ; j < tot ;j++ 刪去 prime * i)
{
int p = prime[j] ;
//篩掉 i * p
//保證p是最小i*p素因子
if(p == 是i的最小質因子) break ;
}
}
實際代碼
for(int i=2;i<=n;i++)
{
if(!num[i])
{
a[cnt++]=i; //統計其中的素數
}
for(int j=0;j<cnt&&i*a[j]<=n;j++)
{
num[i*a[j]]=1;//刪除其素數的倍數
if(i%a[j]==0)//保證是最小質因子
{
break;
}
}
}
gcd , lcm
一些約定
我們規定\(gcd(x,y)\)表示的是\(x,y\)的最大公約數,同時\(lcm(x,y)\)規定為最小公倍數。
規定\(a|b\)表示\(a\)能夠乘除\(b\)。
規定\(a \ \ mod \ \ b\)表示\(a\) %\(b\)
求解
\(1.\) 輾轉相除法(歐幾里得算法)
先來看一下其遞歸式
gcd(int a , int b)
{
return !b ? a : gcd(b , a % b) ;
}
其復雜度是 \(O(log)\) 的
證明
證明 \(gcd(a , b) = gcd(b , a\text{%}b)\)
設 \(r = a \text{%}b , d = gcd(a , b),a = p1\times d , b = p2\times d\)
其中 \(p1,p2\) 互質(這個比較顯然吧,不互質的話還有公約數,那么就不是最大公約數了 ,那么我們就可以得到
\(r = a\text{%}b = a - k \times b = p1\times d - k\times p2 \times d = (p1 - k\times p2) \times d\) , 所以首先我們可以確定 \(r\) 一定是個 \(d\) 的倍數。
感性理解一下,由於我們搞出來的\(a \text{%} b\)是單調不增的,那么我們的值一旦找到,可不就是最大的。
又因為 \(b = p2 \times d\)
我們只需說明 \(p2 , p1 - k\times p2\) 互質即可說明 \(d\) 一定為最大公約數,
證明 \(p2 , p1 - k\times p2\) 互質:
假設 \(p2 . p1 - k\times p2\) 不互質。那么我們就有
把 \(p2 = m\times q\) 帶入可知
所以 \(a = p1\times d , b = p2\times d\) 則\(a = (k\times m + n)q \times d , b = m\times q \times d\)
則 \(a , b\) 的最大公約數為 \(q\times d\) , 則與假設不符,不成立,所以 \(p2 , p1-k\times p2\) 互質。所以 \(r\) 和 \(b\) 的公約數也就是 \(d\)
所以 \(gcd(a, b) = gcd(b , a\text{%}b)\)
聯系
那么 \(lcm\) 和 \(gcd\) 有什么關系呢?
令 \(x = gcd(a,b)\).
則顯然 \(x \mid a\),\(x\mid b\).
令 \(a_0 = [a\ / \ x]\ , \ b_0 = [b\ /\ x]\).
則 \(lcm(a_0 \ , \ b_0) = a_0 \times b_0\). \(gcd(a_0,b_0) = 1\)
\(lcm(a_0,b_0) \times gcd(a_0,b_0) \times x = a_0 \times b_0 \times x\)
又因為 ,最大公約數
所以 , \(lcm(a,b)= \frac {a \times b}{x}\)
也就是 \(lcm(a,b) \times x = a \times b\)
所以 , \(lcm(a,b) \times gcd(a,b) = a \times b\)
證畢,$over \ ~ \ $
整除
【定義】: 如果\(x\) % \(y==0\) , 我們就說, \(y\)整除\(x\) ,記做(上方有約定,但是還是說一下) , \(y|x\) ,
【性質】 :(從數競同學那里嫖來的)
1.若\(b|a\) ,則\(b|(-a) , -b|a , (-b) |(-a) , |b| \ \ | \ \ |a|\) (最后面的是兩個絕對值)
2.滿足轉移性: 若\(a|b\) , \(b|c\) ,則\(a|c\)
3.若\(a,b,c\in Z\) ,且\(a|b , a|c\),則\(a|(b±c) , a| mb , a | mc , a | m(b±c)\),(\(mb\)代表\(m \times b\),沒有罵人的意思,也不是\(mb\)那一個變量的意思,不會吧,不會吧,還有人不知道嗎?)
我們可以將其進行一下推廣到一般情況:
若\(a_i,b_i,c_i \in Z , i = 1 , 2 , 3 … n\),並且滿足\(a_i | b_i\),則有\(a|\sum\limits_{i=1}^{n} b_i \times c_i\),比較顯然吧。
4.設\(a,b\in Z\),且\(a|b\) ,則對於任意的\(m \in Z\) ,都滿足\(am | bm\) ,這是個充要條件。
5.若\(|a| < |b|\) , 且\(|b| \ \ | \ \ |a|\) ,則\(a = 0\)
6.若\(a,b\)互素,且\(p|\prod\limits_{i = 1}^{n} a_i\),則在\(a_1 ,a_2…a_n\)中,至少有一個\(a_i\),滿足\(p\ \ | \ \ a_i\)
7.若\(a,b\)互素,且\(a|b\times c\) ,則\(a|c\)
8.\(n\)個連續整數的乘積必然能被\(n!\)整除。
9.若\(p\)為素數,對任意的正整數\(n\),都滿足\(p | (n ^p - n)\).這性質叫做費馬小定理,證明在求解逆元時會予以證明。
逆元
求解逆元的方法
什么叫做逆元 , 我們認為 \(a \times a^{-1} = 1 (mod \ \ p)\) ,我們稱 \(a^{-1}\) 為 \(a\) 模 \(p\) 意義下的逆元
\(1.\) 遞推求解逆元
假設 \(p = k\times i + r| i > r\)
對兩邊同時乘上 \(i^{-1} , r^{-1}\) 就得到
然后就有了
同時,\(i > r\) ,這就形成了線性遞推關系
// 求 1 -> n的逆元
inv[i] = 1 ;
for(int i = 2 ; i <= n ; i++)
{
inv[i] = (-p/i + p ) * f[p % i] ;
}
\(2.\) 費馬小定理求解逆元。
證明費馬小定理的正確性:
(事實證明,證不出來背過亦可)
占個坑 , 以后證完補。
然后就是一個快速冪的事,不必附代碼
\(3.\) 擴歐求求解逆元。
占個坑,等講完之后有了更深的理解再寫。
逆元的應用
可以進行模意義下除法,我們在模意義下是不能進行除法的,但是我們可以利用逆元將除法轉化成乘法,就行了。
為什么模意義下不能進行除法,因為會導致出現實數,而余數顯示不能為小數。
擴展歐幾里得算法
先證明出歐幾里得顯然在這里變得是比較重要。
鳴謝 : 歐幾里得算法與擴展歐幾里得算法_C++
引理
擴展歐幾里得是用來求解線性同余方程 ,逆元,不定方程的一種算法。
引理 : 對於任意的整數 \(a,b\) ,存在 \(x,y\) 使得 \(gcd(a,b) = a\times x + b\times y\)
證明
當 \(b = 0\) 時 , \(gcd(a,b) = a\) , 此時 , \(x = 1 , y = 0\)
當 \(b\not = 0\) 時
當 \(b = 0\) 時會得到最后的一組解,其他的均可以又上述的推導出來。
代碼實現
inline void exgcd(int a , int b , int x , int y)
{
if(!b)
{
x = 1 , y = 0 ;
return ;
}
else
{
exgcd(b , a%b , x , y) ;
int k = x ;
x = y ;
y = k - (a / b) * y;
}
}
沒有啥模板題讓着寫這玩意證明的。
exgcd 求解不定方程
【鳴謝】
對於一個 \(a\times x + b\times y = c\) 這一個不定方程, \(d = gcd(a,b)\) ,那么顯然的 , \(d|(a\times x + b\times y)\) , 所以,如果 \(c\text{%}d \not = 0\) , 那么就說明是無解的。如果有解的話 :
我們能夠推出一組特解。
很顯然,我們是有 \(a\times x_1+ b\times y_1 = d\) , 同樣的,我們設 \(q \times d = c\) , 將上述式子乘以 \(q\) , 則有
這樣就得到一組特殊解,我們通過特殊解進行推導通解。
我們推導一般的式子,即為
那么我們讓 \(a\times m + b\times n = 0\) ,就可以滿足上述的式子了。
所以我們就有 \(a\times m = -b\times n\) , 同理可以得到 , \(m = t \times \frac{b}{a} , n = -t\times \frac{a}{b}\) , 其中 \(t\) 為任意取得。
exgcd 求線性同余方程
關於一個模方程 \(a \times x \text{%} b = c\) 求解。
我們可以將其轉化成
同理, 就可以得到
然后發現這是一個不定方程,很雞賊,和上面一致即可。
【模板題】
【\(Code\)】
【青蛙的約會】
【\(Code\)】
