數論總結(中) (中階數論)


一.逆元的求解

1.引理:

a.費馬小定理

假如\(a\)是一個整數,\(p\)是一個素數,\(gcd(a,p)=1\),那么有:

\[a^{p-1}≡1(mod(p)) \]

費馬小定理應用:
[1]. 費馬小定理降次:\(p\)是素數,\(a\),\(p\)互質,則\(a^b mod (p)={a^{(b) mod (p-2)}} mod (p)\)
[2]. 求質數逆元:若p是素數,\(\frac{1}{a}mod(p) = a^{p-2} mod(p)\)
注意:不代表\(ax≡1(mod (p))\)\(x\)的最小正整數值是\(p-1\)

b.歐拉定理φ

\(n,a\)為正整數,\(n,a\)互質,即\(gcd(n,a)=1\),則

\[a^{φ(n)}≡1(mod (n)) \]

費馬小定理是歐拉定理的特殊情況,因為當\(n\)為素數時,\(φ(n)=n-1\)
擴展歐拉定理降次:
(1)當\(n>1\),\((a,n)=1\)時, \(a^b \% n=a^{b \% φ(n)} \% n\)
(2)當\(b\leq φ(n)\)時,直接計算即可。
(3)當\(b > φ(n)\)時 , \(a^b \% n = a^{b\% φ(n) + φ(n)} \% n\)
我是不會告訴你這個非常重要的。

歐拉定理應用2:

求解:\(a^x≡1 (mod (Q))\) , \(x>0\)
那么\(x\)的最小解一定是\(φ(Q)\)的約數
由同余的同冪性可以得到\(x\)的解集為 \(φ(Q)\)的 約數與倍數。

歐拉定理的套路技巧

\(ORZ\) \(\ laofu\)隊爺 , 這都能自己 \(yy\) 出來。
我們假設要求多次方,形如\(a^{b^{c^d}} \%p\)這種鬼東西。 那么化式子:

\[a^{b^c }\%p = a^{b^c \% (\ \varphi(p)+[?]\ )}\%\varphi(p) \]

然后\(c\)是對\(\varphi(\varphi(p))\)取模,以此類推遞歸下去。
那么那個\([?]\)我們需要每次都判斷一下真實\(b\)值與\(\varphi(p)\)的大小關系。
這樣非常不好做,這里隊爺們發明了一種非常神奇的做法。
假設我們遞歸到了求\(b^c \% (\ \varphi(p)+[?]\ )\) , 那么代碼如下:

ll Mul(ll x1,ll x2,ll mod)[
    return (x1*x2 < mod) ? (x1*x2) : (x1*x2%mod+mod);
}
ll Pow(ll bs,ll js,ll mod){
    ll S = 1, T = bs;
    while(js){
        if(js&1)S = Mul(S,T,mod);
        T = Mul(T,T,mod);
        js >>= 1;
    }return S;
}
ll Calc(int b,int phi(p)){ll js = Calc(c,phi(phi(p))); return Pow( b,js,phi(p) );}

其中變量名是遞歸求解的,上面的\(b,c,phi(p)\)是表示當前算到\(b^c \% (\ \varphi(p)+[?]\ )\)
這樣做的好處就是不用考慮\(b\)\(\varphi(p)\)的大小關系對求值的影響了。
其實非常簡單,觀察一下我們剛才重載的乘法函數 \(Mul\) ,
如果\(x_1*x_2\)都已經大於\(\varphi(p)\)了,那么后面運算肯定大於\(\varphi(p)\)
所以之后的運算中始終要加上一個\(\varphi(p)\)

2.單個逆元的計算

給定\(a,n\)\((n>1)\),\(gcd(a,n)=1\)計算\(a\)對模\(n\)的乘法逆元\(x\).

方法1:用前面講的Exgcd解方程\(ax≡1(mod (n))\)

\(ax+ny=1\),得\(x\)的特解\(x_0\),則\(a^{-1} mod (n)=(x_0)mod (n)\),解唯一!

方法2:利用歐拉定理\(a^{φ(n)}\)\(≡\)\(1\)\((mod (n))\)

\(a^{-1} mod (n)=(a^{φ(n)-1}mod (n))mod (n)\)
計算\(a^{φ(n)-1}mod (n)\)調用快速冪\(pow(a,φ(n)-1)\)來計算,

方法3:當n為質數時,變為費馬小定理降次:

\(a^{-1} mod (n)=(a^{n-2}mod (n))mod (n)\)

3.線性求解逆元

代碼如下:

inv[1]=1;
for(int i=2;i<=p;i++)
    inv[i]=(M - M/i) * inv[M%i] %M;

證明:

二.中國剩余定理(CRT)。

1.中國剩余定理

2.擴展中國剩余定理

同余方程中的\(n_1,n_2,...,n_k\)不兩兩互質怎么辦?
用擴展中國剩余定理:
兩個方程\(x≡b_1 (mod (a_1))\)\(x≡b_2 (mod (a_2))\)
那么有\(x = a_1*x_1 + b_1 = a_2*x_2 + b_2\);
我們要最小化\(x\),所以最小化\(x_1\)
然后回代得到\(x\)的特解\(x'\),當然\(x'\)也是最小正整數解。
所以\(x\)的通解為:\(x = x' + k*lcm(a_1,a_2)\)
所以得到了一個新的方程: \(x ≡ x' (mod (lcm(a1,a2)))\) ;
所以每次把兩個方程合並成\(x≡x' (mod (lcm(a1,a2)))\)
然后用該方程與接下來的一個聯立,依次求解即可得出結果。
最后得到一個總方程:\(x ≡ C (mod (P))\)
解這個方程即可得到整個方程組的根。

三.MR素數判斷

1.二次勘探定理

\(p\)是質數 、 \(x^2 ≡ 1(mod(p))\)
那么\(x\)的解為 \(x=1\)\(x=n-1\)

2.MR素數判斷

還記得費馬小定理嗎?不記得就在上面
先把模數\(P\)變為\(m*2^k\),然后依次使用二次勘探定理即可。
具體太長了,給一篇博客:戳我!
核心代碼(檢測\(n\)的素性):

//本代碼只測試15次,次數越高,准確率越高。
for (int i = 1; i <= 15; i++){  
    ll a = rand() % (n - 1) + 1;  
    ll x = pow(a, m);     //計算a^m %n
    ll y;  
    for (int j = 1; j <= k; j++){  
        y = mul(x, x);       //計算x*x %n ,使用龜速乘  
        if (y == 1 && x != 1 && x != n - 1)return false;  
        x = y;  
    }  
    if (y != 1)return false;  
}  

實在看不懂背背板子就行了。

四.矩陣乘法

矩陣快速冪要用,這里不講了給一個板子:

struct matrix{
    int a[5][5];
    matrix(){ memset(a,0,sizeof(a)); }
    int *operator [](int x){ return a[x]; }
    matrix operator*(matrix &b){
        matrix c; 
        for(int i = 0 ; i < n ; i ++)
			for(int j = 0 ; j < n ; j ++)
				for(int k=0 ; k < n ; k ++)
					c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j])%mod;
        return c;
    } 
}T,S;

四.高斯消元

1.高斯消元求解方程組(Gauss)。

百度一下,你就知道,這里只給代碼實現。
注:mp[n][n+1]為方程矩陣,其中mp[i][n+1]為第i個方程的常數項。
當然最后答案也存在mp[i][n+1]中,代碼中輸出\(No\) \(Sol\)是指有無數多個解。
具體看\(Luogu\)的板子題:戳這里!
補:省選中的高斯消元模板題:戳這里!

int main(){
    cin >> n;
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n + 1; j ++)
            cin >> mp[i][j];   
    for(int j = 1; j <= n; j ++){
        int rgt = 0;
        for(int i = j; i <= n; i ++)
            if(mp[i][j]){rgt = i; break;}
        if(!rgt)continue;
        if(rgt ^ j)swap(mp[rgt],mp[j]);
        if(mp[j][j] == 0){cout<<"No Solution"; return 0;}
        for(int i = j + 1; i <= n; i ++){
            double div = mp[i][j] / mp[j][j];
            for(int k = 1; k <= n + 1; k ++)mp[i][k] -= div*mp[j][k];
        }
    }
    for(int j = n; j >= 1; j --){
        mp[j][n+1] =  mp[j][n+1] / mp[j][j];
        for(int i = j-1; i >= 1; i --)mp[i][n+1] -= mp[j][n+1] * mp[i][j];
    }
    for(int i = 1; i <= n; i ++)printf("%.2lf\n" ,mp[i][n+1]);
    return 0;
}

2.高斯消元求解異或方程(Gauss_Xor)

其實差不多,具體流程如下:
(1)找到當前列系數不為0的一行,並將其交換到當前行。
(2)用當前行去消 當前列系數不為0的所有行 , 只是運算為異或罷了。
(3)消到最后只剩下一個元,解出來。
(4)向上一路回帶即可(具體怎么回帶自己手玩一把即可)。
注意一下:
假設消除到某一行
(1)若所有系數都為0,而常數項不為0,那么則無解。
(2)若所有系數都為0,且常數項為0,那么則有無窮多個解。
然后常用的搭配為bitset(一個STL),真的是卡常數神器。
具體的使用方法給一篇博客:http://blog.csdn.net/qll125596718/article/details/6901935
一道板子題:[SDOI2010]外星千足蟲
然后這題有點難度:[HNOI2011]XOR和路徑
具體代碼:(以上面的例題為例)

#include<bits/stdc++.h>
#define ll long long
#define IL inline
#define RG register
using namespace std;
IL int gi(){
    RG int date = 0, m = 1;  RG char ch = 0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
    if(ch == '-'){m = -1; ch = getchar();}
    while(ch>='0'&&ch<='9'){date=date*10+ch-'0';ch=getchar();}
    return date*m;
}

int n,m,Round;
bitset<2050>mp[2050]; char s[2050][2050];


IL bool Gauss_Xor(){
    for(RG int j = 1; j <= n; j ++){
        RG int rgtpos = 0;
        for(RG int i = j; i <= m; i ++)
            if(mp[i][j]){rgtpos = i; break;}
        //找到一個當前位不為0的方程....
        if(!mp[rgtpos][j])return false;   //無解       
        if(rgtpos != j)swap(mp[j] , mp[rgtpos]);
        Round = max(Round,rgtpos);
        for(RG int i = j+1; i <= m; i ++)
            if(mp[i][j])mp[i] ^= mp[j];
    }
    for(RG int j = n; j >= 1; j --){
        //mp[j][n+1] 此時即為解;
        for(RG int i = j-1; i >= 1; i --)
            mp[i][n+1] = mp[i][n+1] ^ (mp[i][j]*mp[j][n+1]);
    }
    return true;
}

int main(){
    n = gi(); m = gi();           //有m(m>=n)個方程,每個方程左邊有n個系數.
    
    for(RG int i = 1; i <= m; i ++){
        scanf("%s",s[i]+1);
        for(RG int j = 1; j <= n; j ++)
            mp[i][j] = s[i][j] - '0';
        mp[i][n+1] = gi();
    }	
    Round = 0;
    if(!Gauss_Xor())printf("Cannot Determine");    //無解
    else{
        printf("%d\n",Round) ;
        for(RG int i = 1; i <= n; i ++)
            puts(mp[i][n+1] ? "?y7M#" : "Earth");
    }return 0;
}

五.組合數學。

1.數學表示:

\(C_m^n\)表示在\(m\)個中選\(n\)個的方案數。 (把\(m\)無區別物品放到\(n\)有區別籃子的方案數)
\(P_m^n\)表示在\(m\)個中選\(n\)個的排列數。 (把\(n\)有區別物品放到\(m\)有區別籃子的方案數)
\(S_m^n\)表示斯特林數\(S(n,m)\)。 (把\(n\)有區別物品放到\(m\)無區別籃子,籃子不空的方案數)

2.常用公式:

\[C_n^m = C_{n-1}^{m-1}+C_{n-1}^{m} \]

\[\prod_{n-m+1}^n = C_n^m*{m!} \]

\[n^m = \sum_{j=1}^{n}S^m_j*\prod_{n-j+1}^n =\sum_{j=1}^nS_j^m*{j!}C_n^j \]

\[C_n^k = C_n^{n-k} \]

\[(a+b)^n = \sum_{k=0}^nC_n^ka^{n-k}b^k(二項式定理) \]

\[S_m^n=S_{m}^{n-1}*m+S_{m-1}^{n-1} \]

\[C_n^{k+1} = C_n^k*\frac{n-k}{k+1} \]

\[S_m^n = 0(if(m>n)) \]

\[\sum_{k=1}^n C_n^k*C_k^t = C_n^t * 2^{n-t} \]

\[m!*S_m^n = \sum_{i=0}^m (-1)^iC_m^i*(m-i)^n \]

自己用組合意義推一下即可,都不是很難。

3.可重組合數學:

a.可重排列

\(k\)個元素,其中第\(i\)個元素有\(n_i\)個,求全排列數。

\[P' = \frac{({ \Sigma_{i=1}^k n_i})!}{{n_1!}{n_2!}....{n_k!}} \]

即先做全排列,然后給每個元素編號,具體見藍書P104

b.可重組合

\(n\)個元素,每個元素可以選無窮多個,一共選\(k\)個,求方案數。

\[C' = C^{n-1}_{k-n+1} = C^{k}_{k-n+1} \]

假設第\(i\)個元素選\(x_i\)個,那么原問題變為\(x_1+x_2+.....+x_n=k\)
我們令\(y_i = x_i + 1\),那么\(y_1+y_2+y_3+....+y_n = k+n\)
此時\(y>0\),即每個元素都要選。 所以等於在\(k+n\)個元素(\(k+n-1\)個空位)間放\(n-1\)個隔板。

六.數論分塊。

這其實是因題目而定的啦。這里主要是講這種思路(套路)。
我們假設求解\(\sum_{i=1}^n \lfloor\frac{n}{i}\rfloor\)
那么應該怎么在\(\sqrt{n}\)的時間里求出來?
觀察到\(\lfloor\frac{n}{i}\rfloor\)的取值只有\(\sqrt{n}\)個。
所以可以類似分塊算法那樣搞一個數論分塊。
定理:若有一個值\(i\),那么數論分塊中其同值上界為:

\[ceil = \biggl\lfloor\ \frac{n}{\lfloor\frac{n}{i}\rfloor} \biggr\rfloor \]

即在\([i,ceil]\)這一段區間內,\(\lfloor\frac{n}{i}\rfloor\)的取值是一樣的。所以就可以直接計算這一整塊的貢獻。
具體代碼如下(以求\(\sum_{i=1}^n \lfloor\frac{n}{i}\rfloor\)為例):

int l = 1 , r , ans = 0;
while(l<=n){
    r = n/(n/l);    
    ans += (r-l+1)*(n/i);
    l = r + 1;
}

思考一下如果是二維怎么辦,如求\(\sum_{i=1}^{min(n,m)} \lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor\)
其實也非常簡單啦,對於\(i\)\(j_1 = n/\lfloor\frac{n}{i}\rfloor\) , \(j_2 = m/\lfloor\frac{m}{i}\rfloor\) , 那么\(j = min(j_1,j_2)\)
所以每次都取\(min\),然后不斷跳即可。
數論分塊真的非常重要,在后面的高級數論(如莫比烏斯反演)中會經常用到。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM