NOIP數論內容整理
注:特別感謝sdsy的zxy神仙以及lcez的tsr筮安幫助審稿
一、整除:
對於\(a,b~\in~Z\),若\(\exists~k~\in~Z\),\(s.t.~b~=~k~\times~a\),則說\(a\)整除\(b\),記做\(a~|~b\)
二、帶余除法:
\(~\forall~a,b~\in~z\)存在且僅存在唯一的\(q,r~\in~Z^*\),\(s.t.~b~=~q~\times~a+r\),其中\(r~\in~[0,a)\)。記做\(r~=~b~Mod~a\)。
三、公約數
設\(a,b~\in~Z\),若\(~\exists~k,x,y~\in~Z^*\),\(s.t.~a~=k~\times~x,b~=~k~\times~y\),則說\(k\)是\(a,b\)的公約數。公倍數同理。
四、\(gcd\)與\(lcm\)
記\(a,b\)的最大公約數為\(gcd(a,b)\),最小公倍數為\(lcm(a,b)\)
五、最大公約數與最小公倍數乘積性質定理
性質:\(a~\times~b=gcd(a,b)~\times~lcm(a,b)\)
六:最大公約數的求取:(以下不妨設\(b~\leq~a\))
更相減損術:\(gcd(a,b)~=~gcd(b,a-b)\)
歐幾里得算法:\(gcd(a,b)~=~gcd(b,a~Mod~b)\)
其中,更相減損術的復雜度是\(O(n)\),歐幾里得算法的復雜度是\(O(logn)\)。其中\(n~=~\max(a,b)\)
七:更相減損術的優化
引理:\(\forall~m~\neq~0,~a,b~\in~Z\),有\(m~\times~gcd(a,b)=gcd(ma,mb)\)
當\(a,b\)是兩個偶數時,顯然\(gcd(a,b)\)有一因數\(2\)。於是\(gcd(a,b)~=~2~\times~gcd(\frac{a}{2},\frac{b}{2})\)
當\(a,b\)一奇一偶的時候,不妨設\(a\)是偶數。顯然\(gcd(a,b)\)不含因子\(2\)。於是有\(gcd(a,b)=gcd(\frac{a}{2},b)\)
當\(a,b\)同為奇數時,直接應用更相減損術。\(gcd(a,b)=gcd(b,a-b)\)。
考慮兩個奇數相減答案顯然是偶數。於是一次更相減損術顯然對應一個數除以2的操作。即更相減損的次數與除以二的操作次數同階。考慮一個數最多被除\(log\)次。於是該算法的復雜度為\(O(logn)\)。
該算法常用在對兩個高精度數求\(gcd\),因為兩個高精度數做除法的復雜度難以承受,從而應用該算法。
八、例題:
給定一個序列,要求支持區間加法。多次查詢區間內所有數字的\(gcd\)。\(n,m,a_i~\leq~10^5\)
Solution:
因為區間加法無法維護\(gcd\),所以顯然不能暴力線段樹。考慮對原序列做差分。由更相減損定理,顯然成立\(gcd(a,b,c)~=~gcd(a,b-a,c-b)\)。於是差分后區間加法改為單點修改操作。於是一次操作的復雜度為\(O(log^2n)\)。總時間復雜度為\(O\left(m\log^2n\right)\),可以通過本題。
九、擴展歐幾里得算法
裴蜀定理:關於\(x,y\)的方程\(ax+by=c\)有解當且僅當\(gcd(a,b)|c\)。
求關於\(x,y\)的方程\(ax+by=c\)的一組整數解。
不妨設\(c=gcd(a,b)\)。否則左側乘一常數\(k\),不失一般性
根據歐幾里得算法,有
於是有
於是有
根據對應系數相等,顯然有\(x=y_0,y=x_0-\left\lfloor\frac{a}{b}\right\rfloor~y_0\)。考慮他的一組特解:當\(b=0\)時,顯然\(x=1,y=0\)成立。
求上述方程的所有解
假設求出的該方程的一組特解\(x=x_0,y=y_0\),則該方程的所有解為\(x=x_0+\frac{k~\times~b}{gcd(a,b)},y=y_0-\frac{k~\times~a}{gcd(a,b)}\)。
十、素數:
有且僅有\(1\)和本身兩個因子的數是素數
十一、埃拉托色尼篩法:
對每個數只篩掉它的倍數。
int pcnt;
int prime[maxn];
bool is_not_prime[maxn];
void Get_Prime(int x) {
is_not_prime[1]=true;
for(int i=1;i<=x;++i) if(!is_not_prime[i]) {
prime[++pcnt]=i;
for(int j=i*i;j<=x;j+=i;) is_not_prime[j]=true;
}
}
十二:歐拉篩法
對每個數只被他的最小素因子篩掉
int pcnt;
int prime[maxn];
bool is_not_prime[maxn];
void Get_Prime(int x) {
is_not_prime[1]=true;
for(int i=2;i<=x;++i) {
if(!is_not_prime[i]) prime[++pcnt];
for(int j=1;j<=pcnt;++j) {
if(i*prime[j] > x) break;
is_not_prime[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
}
十三:在\(O(nlogn)\)時間內篩除\(n\)以內所有數的素因子
對於每個數記錄自己的最小素因子。對於第每個數,迭代將每個數除以自己的最小素因子。
int pcnt;
int prime[maxn],pre[maxn];
bool is_not_prime[maxn];
void Get_Prime(int x) {
is_not_prime[1]=true;
for(int i=2;i<=x;++i) {
if(!is_not_prime[i]) prime[++pcnt],pre[i]=pcnt;
for(rg int j=1;j<=pcnt;++j) {
if(i*prime[j] > x) break;
is_not_prime[i*prime[j]]=true;
pre[i*prime[j]]=j;
if(!(i%prime[j])) break;
}
}
}
void ans(int x) {
for(int i=1;i<=x;++i) {
printf("%d:",i);
int di=i;
while(di != 1) printf("%d",prime[pre[di]]),di/=prime[pre[di]];
putchar('\n');
}
}
十四、唯一分解定理:
\(\forall~x~\in~Z^*\),存在且僅存在一個形如\(x=p_1^{c_1}~p_2^{c_2}~...~p_k^{c_k}\)的等式。其中滿足\(p_i ~<~p_{i+1},p_i\)為質數,\(c_i~\in~Z\)
則對於\(a,b\)的\(gcd,lcm\),其唯一分解式對應位置的指數取\(\min,\max\)即為對應的\(gcd,lcm\)的唯一分解式
十五、歐拉phi函數:
定義:\(\phi(n)\)為\([1,n)\)中與\(n\)互質的數的個數
\(\phi(n)~=~n~(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_k})\)
其中\(p_i\)為\(n\)的唯一分解式對應底數。
證明:不妨設\(n\)只有\(p,q\)兩個因數。否則做數學歸納
則與\(n\)互質的數的個數為\(n\)減去\(p\)的倍數和\(q\)的倍數。根據容斥原理,應加回\((pq)\)的倍數。即
對於\(n\)有更多因數的情況,可以依據唯一分解定理做數學歸納。證畢。
求單個數字的\(\phi\)函數:
暴力枚舉質因數。復雜度\(O(\sqrt{n})\)
埃拉托色尼篩法:
對每個質數,修改他的倍數的\(phi\)函數值
int pcnt;
int prime[maxn],phi[maxn];
bool is_not_prime[maxn];
void euler(int x) {
for(int i=1;i<=x;++i) phi[i]=i;
for(int i=2;i<=x;++i) if(!is_not_prime[i]) {
prime[++pcnt]=i;phi[i]=i-1;
for(rg int j=i*i;j<=x;j+=i) {
is_not_prime[j]=true;
phi[j]=phi[j]/i*(i-1);
}
}
}
歐拉篩:
對每個數,只被他的最小質因子篩掉。
考慮通過一個質因子求出他的歐拉函數值。
引理:\(\forall x\)為質數,顯然\(\phi(x)=x-1\)。
定理一:\(\forall~x~\in~Z^*,p|x\),若\(\frac{x}{p}\)與\(p\)不互質,則\(\phi(x)=\phi(\frac{x}{p})~\times~p\)
證明:
不妨設 \(x\) 有且僅有 \(p,q\) 兩個質因子,否則對\(q\)做數學歸納,不失一般性
則 \(q~=~\frac{x}{p}\)
於是由容斥原理有
上式除以下式,得
移項整理后,原式得證。
證畢。
定理二:\(\forall~x~\in~Z^*,p|x\),若\(\frac{x}{p}\)與\(p\)互質,則\(\phi(x)=\phi(\frac{x}{p})~\times~(p-1)\)
證明:
易證\(phi\)函數為積性函數。因為\(\frac{x}{p}\)與\(p\)互質,於是\(\phi(x)=\phi(\frac{x}{p})~\times~\phi(p)\)
又因為\(p\)是一個質數,於是根據引理,\(\phi(p)=p-1\)。
原式得證。
證畢。
於是對於每個數,若他是質數,則應用引理,否則在篩時,若最小質因子與他互質,則應用定理二,否則應用定理一。
int pcnt;
int prime[maxn],phi[maxn];
bool is_not_prime[maxn];
void euler(int x) {
phi[1]=1;
is_not_prime[1]=true;
for(int i=1;i<=x;++i) {
if(!is_not_prime[i]) prime[++pcnt]=i,phi[i]=i-1;
for(int j=1;j<=pcnt;++j) {
if(i*prime[j] > x) break;
is_not_prime[i * prime[j]]=true;
if(!(i%prime[j])) {phi[i*prime[j]]=phi[i]*prime[j];break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
十六、模方程:
定義:\(\forall a,b ~\in~Z\),若\(a~Mod~m~=~b~Mod~m\) 則稱作\(a,b\)在模\(m\)域下同余。記做\(a~\equiv~b~(Mod~m)\)。
同余式兩邊支持同時加、減、乘同一個數字,但不支持除法。
十七、模逆元:
\(\forall~a~\in~Z\),若\(\exists~x~\in~Z,s.t.~ax~\equiv~1~(Mod~m)\)則稱\(x\)是\(a\)在模\(m\)域下的逆元。在模\(m\)域下,任何一個整數除以\(a\)完全等價於乘\(x\)。
一般而言,\(m\)為質數是\(a\)存在逆元的充分條件
十八、逆元的求法
單個數求逆元
解方程\(ax~\equiv~1~(Mod~m)\),發現等價於\(ax+km=1\)。直接使用\(exgcd\)求得答案即可。
線性篩逆元:
記\(x\)的逆元為\(x^{-1}\),數組表示為\(inv_x\)
則有線性遞推式:\(inv_i~=~(-\left\lfloor\frac{m}{i}\right\rfloor~\times~inv_{m~Mod~i}+m)~Mod~m\)
證明:
對於所有的\(i\),寫出他的帶余除法表達式:
在\(Mod~m\)域下有:
等式兩側同乘\(i^{-1}~\times~r^{-1}\)
化簡,整理得到:
因為\(k~=~\left\lfloor\frac{m}{i}\right\rfloor\),原式得證。
int inv[maxn];
void Get_inv(int x,int p) {
inv[1]=1;
for(int i=2;i<=x;++i) inv[i]=(p-p/i)*inv[p%i]%p;
}