# Combination 也就是C n取k,由公式直接計算 ``` n n! C = ----------- k (n-k)!*(k)! ``` Code ```cpp= int C(int n,int k){ int top=1,down=1; for(int i=n;i>n-k;i--) top*=i; for(int i=k;i>0;i--) down*=i; return top/down; } ``` ### 加速和避免溢位的方法:一邊乘一邊除 Code ```cpp= int C(int n,int k){ int ans=1; for(int x=n,y=1; x>n-k || y<=k; x--,y++){ if(x>n-k) ans*=x; if(y<=k) ans/=y; } return ans; } ``` 如果要把答案取餘數的話就比較麻煩了,要用到費馬小定理 ### 模逆元 因為取餘數不可用在除法上,所以對於我們的公式就要改成 ``` 1 1 n! * ------- %m * ------- %m (n-k)! k! ``` 但要怎麼計算倒數取模呢?這時候費馬小定理就派上用場了 ## 費馬小定理 定義: 對於任意正整數a和質數p ``` a^p-1 ≡ 1 (mod p) a^p-1 %p == 1 %p ``` 像是 (a=2,p=5) 2^5-1^%5=16%5=1 (a=3,p=5) 3^5-1^%5=81%5=1 (a=4,p=3) 4^3-1^%3=16%3=1 所以我們想要求1/a可以把費馬小定理的兩邊同除a a^p-1^/a ≡ 1/a (mod p) a^p-2^ ≡ 1/a (mod p) 所以inv(a)≡a^p-2^(mod p),這樣就解決了我們的問題點:<b>倒數取模</b> 公式: ``` n m-2 m-2 C = n! * (n-k)! * %m k! %m k ``` 次方計算可以用快速冪,階乘和反乘階可以預處理,要用的時候直接拿就好了 Code ```cpp= #include <bits/stdc++.h> #define int long long using namespace std; #define MAXN 100 const int mod = 1e9+7; int f[MAXN], inv[MAXN]; int powf(int a,int b){ int ans = 1; while(b){ if(b & 1) ans = (ans * a) % mod; a = (a * a) % mod; b >>= 1; } return ans; } int C(int a,int b){ if(a < b) return 0; return f[a] * inv[b] % mod * inv[a - b] % mod; } signed main(){ //預處理 f[0] = inv[0] = 1; for(int i = 1 ;i < MAXN; i++){ f[i] = (f[i - 1] * i) % mod; //i的階乘 inv[i] = powf(f[i], mod - 2); //i的反階乘 } int n,k; cin >> n >> k; cout << C(n, k); } ```