約數、素數、gcd(最大公約數)、lcm(最小公倍數)
除法和模運算
a%b=a-a/b*b 其中a/b是整數除法
約數和倍數
如果兩個數字a,b,滿足a%b=0,那麼我們就說a是b的倍數,b是a的約數,記作b|a 通常情況下只考慮正約數和正倍數
求約數
求數字n的所有約數:
1:O(n):從1列舉 n%i==0
2:O(n^0.5):約數總是成對出現,如果有a/b=c,就一定會有a/c=b,就可以只列舉到n^0.5就可以
int cnt, fac[N];//約數個數和約數 for(int i = 1; i * i <= n; i ++){//不要使用sqrt if(n % i == 0){ cnt++; fac[cnt] = i; if(i * i != n){ cnt ++; fac[cnt] = n / i; } } }
求倍數
一個數字的倍數有無窮多個,所以通常只求出n以內的a的所有倍數
對於一個數字a,倍數一定是a,2a...n/a*a,所以可以列舉每次加a
質數判定與質約數
質數,也叫素數。如果一個數字的約數只有1和它本身,則這個數就是質數。如果一個數的約數超過兩個,則為合數。
1既不是質數也不是合數
質約數:既是一個數的約數同時本身也是一個質數
判定一個數是否是質數
int ans = 1;//為1表示是質數,為0表示不是質數 for(inti = 2; i * i <=n; i ++){//注意從2開始 if(n % i == 0 ){ ans = 0; break ; } }
算數基本定理:
任何一個大於1的自然數N,如果N不是質數,都可以唯一分解成有限個質數,即N=(P1^a1)*(p2^a2)....*(pn^an)
p1<p2<...<pn,P都是質數,a都是正整數
這個定理在數論中非常重要。切記切記
約數倍數的特徵
如果一個數字x是N的約數,那麼x的質約數,N中一定存在,並且N中的質約數,x中可以沒有。並且x的質約數的指數一定小於等於N中相同質約數的指數
同理x是N的倍數,那麼上面的結論就會反過來
求質約數
一個數字n最多有一個>n^0.5的質約數,所以我們仍然去哪隻需要列舉到n^0.5
一個非常樸素的方式是列舉每個數字,判斷是否是約數並判斷是否是素數,複雜度接近於O(n)考慮一個數字n=(p1^a1)*(p2^a2)...*(pk^ak),其中p1<p2<p3...<pk.當我們從2列舉到n^0.5的時候,第一個滿足i|n的i一定是p1,此時我們遇到了一個因子,當然也是質因子
每遇到一個質約數就將其除光,下一個約數一定是質約數。
如果最後的n!=1,那麼說明剩下了一個大於n^0.5的質數(最多也只會存在一個),同時也是初始n的一個約數,也要被計入
int prime_fac[N], cnt; for(int i = 2; i * i <= n; i ++) { if(n % i == 0){ cnt ++; prime_fac[cnt] = i; } while(n % i == 0 ) n /= i;//這樣n就會不斷變小,這樣是對的 } if(n != 1 ){ cnt ++; prime_fac[cnt] = n; }
n=(p1^a1)*(p2^a2)*..*(pk^ak),p1<p2<p3..<pk.
n的約數的個數:(a1+1)*(a2+1)*(a3+1)*..*(ak+1)。對於p1而言一共有a1+1種可能
n的約數和:(p1^0+p1^1+..+p1^a1)*...*(pk^0+pk^1+...+pk^ak).
另t=p2^a2*...*pk^ak,那麼S(n)=p1^0*S(t)+p1^1*S(t)+....+p1^a1*S(t).再對S(t)進行分解就可以了
求最大公約數和最小公倍數
gcd(x,y):對於兩個數字x,y,如果d既是x的約數也是y的約數,則d是x,y,的公約數,最大的d就是x,y的最大公約數
lcm(x,y):對於兩個數字x,y,如果d既是x的倍數也是y的倍數,則d是x,y,的公倍數,最小的d就是x,y,的最小公倍數
特殊的,如果兩個數字x,y,的最大公約數gcd(x,y)是1,則這兩個數字互質。
求最大公約數
通常使用輾轉相除法來實現
輾轉相除法:兩個數的最大公約數等於其中較小的那個數和兩個數相除餘數的最大公約數
gcd(a,b)=gcd(b,a%b)
複雜度O(logmax(a,b))
int gcd(int a,int b){ if(b == 0) return a; return gcd(b , a % b); }
如果給定的x,y,是以質因數乘積的表示式
x=(p1^a1)*(p2^a2)...*(pk^ak) . ai>=0
y=(p1^b1)*(p2^b2)...*(pk^bk). bi>=0
等於0是說,如果x中某個質因數pi,y中沒有那麼y中的bi就等於0
gcd(x,y)=(p1^min(a1,b1))*(p2^min(a2,b2))...*(pk^min(ak,bk))
lcm(x,y)=(p1^max(a1,b1))*(p2^max(a2,b2))...*(pk^max(ak,bk))
並且可以知道x*y=gcd(x,y)*lcm(x,y)
在c++的algorithm中存在一個函式 __gcd(x,y). 其中x,y,是int
寫於: 2020/8/20 11:59