基本運算
取模(mod)取余(rem)
定義
- 給定一個正整數p,任意一個整數n,一定存在等式 :
- n = kp + r ;
- 其中 k、r 是整數,且 0 ≤ r < p,則稱 k 為 n 除以 p 的商,r 為 n 除以 p 的余數。
- 對于正整數 p 和整數 a,b,定義如下運算:
- 取模運算:a % p(或a mod p),表示a除以p的余數。
- 模p加法: a+b算術和除以p的余數。(a + b) % p = (a % p + b % p) % p
- 模p減法: a-b算術差除以p的余數。(a - b) % p = (a % p - b % p) % p
- 模p乘法: a*b算術乘法除以p的余數。(a * b) % p = (a % p * b % p) % p
由以上定義易證歐幾里得算法的正確性
- 定義(n,p)為n和p的最大公約數,要證明歐幾里得算法正確性即證明(n,p)=(p,r);
- 設n,p的公因數為g,則g|n且g|p,由n = kp + r 得到g|r('|'為整除);
- 則n和p的最大公約數也是p和r的最大公約數.
取模和取余的區別
對于整型數a,b來說,取模運算或者取余運算的方法都是:
- 求 整數商: c = a/b;
- 計算模或者余數: r = a - c*b.
求模運算和求余運算在第一步不同: 取余運算在取c的值時,向0 方向舍入,而取模運算在計算c的值時,向負無窮方向舍入。
例如:
- 10 mod(-4)=-3
- 10 rem(-4)=-2
歸納:
- 當a和b符號一致時,求模運算和求余運算所得的c的值一致,因此結果一致。
- 當符號不一致時,結果不一樣。求模運算結果的符號和b一致,求余運算結果的符號和a一致。
整除
若a除以b(b不等于0,a、b都為整數),商為整數且余數為0,則叫做a能被b整除或者b能整除a,記作b|a
整除的基本性質
<blockquote>
①若a|b,a|c,則a|(b±c)。</br>
②若a|b,則對任意c(c≠0),a|bc。</br>
③對任意非零整數a,±a|a=±1。</br>
④若a|b,b|a,則|a|=|b|。</br>
⑤如果a能被b整除,c是任意整數,那么積ac也能被b整除。</br>
⑥如果a同時被b與c整除,并且b與c互質,那么a一定能被積bc整除,反過來也成立。a|bc,(a,b)=1 => a|c
</br>
對任意整數a,b,b>0,存在唯一的數對q,r,使a=bq+r,其中0≤r< b,這個事實稱為帶余除法定理,是整除理論的基礎。</br>
若c|a,c|b,則稱c是a,b的公因數。若d是a,b的公因數,d≥0,且d可被a,b的任意公因數整除,則d是a,b的最大公因數。若a,b的最大公因數等于1,則稱a,b互素,也稱互質。累次利用帶余除法可以求出a,b的最大公因數,這種方法常稱為輾轉相除法。又稱歐幾里得算法。</br>
</blockquote>
同余
設m是大于1的正整數,a、b是整數,如果(a-b)|m,則稱a與b關于模m同余,記作a≡b(mod m),讀作a與b對模m同余.
性質
- 反身性 a≡a (mod m)
- 對稱性 若a≡b(mod m),則b≡a (mod m)
- 傳遞性 若a≡b (mod m),b≡c (mod m),則a≡c (mod m)
- 同余式相加 若a≡b (mod m),c≡d(mod m),則a±c≡b±d (mod m)
- 同余式相乘 若a≡b (mod m),c≡d(mod m),則ac≡bd (mod m)
最大公約數(gcd 即 Greatest Common Divisor)
最大公因數,也稱最大公約數、最大公因子,指兩個或多個整數共有約數中最大的一個。
性質
記gcd=gcd(a,b)
- a=mgcd(a,b),b=ngcd(a,b),則(m,n)=1,即m和n互素
- gcd一定可以表示為a和b的線性組合,即ax+by=gcd
- gcd是a和b的線性組合所能表示出的最小正整數
gcd怎么求?
歐幾里得算法(輾轉相除法)
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
由性質2得出該方程一定有解,因此引入擴展歐幾里得算法
- extend_gcd(a,b)表示求出ax+by=gcd(a,b)的一組解(x,y)
- 由a=(a/b)b+a%b得((a/b)b+a%b)x+by=gcd(a,b)即((a/b)x+y)b+x*(a%b)=gcd(b,a%b)=gcd(a,b)
- 設extend_gcd(b,a%b)求出的一組解為(x2,y2)
- x=y2,y=x2-(a/b)y2那么extend_gcd(a,b)的解可以用(y2,x2-(a/b)y2)表示
擴展歐幾里得算法
int extend_gcd(int a,int b,int &x,int &y){
int d=a;
if(b!=0){
d=extend_gcd(b,a%b,y,x);
y-=(a/b)*x;
}
else{
x=1;
y=0;
}
return d;
}
由擴展歐幾里得計算出的(x,y)不是方程ax+by=gcd(a,b)的唯一解,因為對任意整數k,令g=gcd(a,b)
- a(x+k(b/g))+b(y-k(a/g))=ax+by+kab/g-kab/g=g
- 即(x,y)如果為ax+by=g的一組解,那么(x+k(b/g),y-k(a/g))也是一組解。
- 用擴展歐幾里得算法可以求出滿足ax+by=gcd(a,b),x1≤x≤x2,y1≤y≤y2的所有解
最小公倍數
若有一個數X,可以被另外兩個數A、B整除,且X大于(或等于)A和B,則X為A和B的公倍數。A和B的公倍數有無限個,而所有的公倍數中,最小的公倍數就叫做最小公倍數。兩個整數公有的倍數稱為它們的公倍數,其中最小的一個正整數稱為它們兩個的最小公倍數。同樣地,若干個整數公有的倍數中最小的正整數稱為它們的最小公倍數。記作lcm(A,B),其中lcm是英語中“最小公倍數”一詞(lowest common multiple)的首字母縮寫。
lcm(a,b)=a/gcd(a,b)*b
一元線性同余方程ax≡b(mod c)
- ax≡b(mod c)該方程有解,當且僅當b能被a與c的最大公約數整除,記作gcd(a,c)|b,記g=gcd(a,c)。
- 如果x為該方程的解,那么該方程所有的解可以表示為{x+k*c/g |k∈Z}
- 上述方程等價于ax+cy=b
- b%g!=0則方程無解 例如:3x≡2(mod 6) gcd(3,6)=3 3不整除2,方程無解。
- b%g=0時,用擴展歐幾里得算法可以求出(x,y),使得ax+cy=g,則a(b/g)x+c(b/g)y=b,所以x=x(b/g)為該方程的一個解,進而可知原方程的所有解可以表示為{x+k(c/g) | k∈Z}。
- 求特殊解:由5可知,x=x*(b/g)是該方程的一個解,其他解都關于c/g與x同余,在模c下,共有c/g個解。
例如:
12x ≡ 20 (mod 28)中,g=gcd(12.28)=4,它的所有解為{4,11,18,28},關于7與x同余。記mod=c/g最小正整數解可以表示為 (x%mod+mod)%mod
Code
int linear(int a,int b,int c){
int x,y;
int g=extend_gcd(a,c,x,y);
if(b%g)
return -1;
x=x*(b/g);
int mod=c/g;
x=(x%mod+mod)%mod;
return x;
}
素數的篩選
- 素數:若一個大于1的整數除1和本身外無其他因子,則這個數是素數
- 合數:若一個大于1的整數不是素數,則其是合數
- 1既不是素數也不是合數
最經典的一種篩法-埃氏篩法(埃拉托斯特尼篩法)
核心思想:如果i是素數,那么對于所有的j≥2,i*j都不是素數
Code
int prime[maxn],res;
bool is_prime[maxn];
void get_prime(int n){
res=0;
memeset(is_prime,0,sizeof(is_prime));
is_prime[0]=is_prime[1]=1;
for(int i=2;i<=n;i++)
if(!is_prime[i]){
prime[res++]=i;
for(int j=2;j*i<=n;j++) is_prime[j*i]=1;
}
}
素因子分解
任意一個正整數都能分解成若干個素數乘積的形式
給定一個整數n,n可以表示為n=(p1a1)*(p2a2)......(pi^ai)的形式
pi為素數且互不相等。
Code
int fact[maxn][2],cnt;
void get_factor(int n){
cnt=0;
for(int i=2;i*i<=n;i++)
if(n%i==0){
fact[cnt][0]=i;
fact[cnt][1]=0;
while(n%i==0){
n/=i;
fact[cnt][1]++;
}
cnt++;
}
if(n>1) fact[cnt][0]=n,fact[cnt++][1]=1;
}