给定 n 组询问,每组询问给定两个整数 a,b,请你输出\(C_a^b\mod(1e9 + 7)\) 的值。
求组合数Ⅰ
时间复杂度:O(\(n^2\) )
\(1\leq n\leq 10000,1\leq b\leq a\leq
2000\)
数据量较小,直接将所有可能初始化
\(C_a^b=C_{a-1}^{b-1}+C_{a-1}^b\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;const int N = 2e3 + 10 , mod = 1e9 + 7 ;long long C[N][N];int n;void Init () { for (int i = 0 ; i < N; i++) for (int j = 0 ; j <= i; j++) if (j == 0 ) C[i][j] = 1 ; else C[i][j] = (C[i - 1 ][j - 1 ] + C[i - 1 ][j]) % mod; } int main () { Init (); cin >> n; while (n--) { int a, b; cin >> a >> b; cout << C[a][b] << '\n' ; } return 0 ; }
求组合数Ⅱ
时间复杂度:O(nlogn)
\(1\leq n\leq 1000,1\leq b\leq a\leq
10^5,mod = 1e9 + 7\)
\(C_a^b=\frac{a!}{b!(a-b)!}=a!\times
b!^{-1}\times (a-b)!^{-1}\)
\(b!^{-1} = ((b-1)!b)^{-1}=(b-1)!^{-1}b^-1
= (b-1)!^{-1}b^{m-2}\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> using namespace std;typedef long long ll;const int N = 1e5 + 10 , mod = 1e9 + 7 ;ll f[N], inf[N], n; ll qmi (ll a, ll b, ll p) { ll ans = 1 ; while (b) { if (b & 1 ) ans = ans * a % p; a = a * a % p; b >>= 1 ; } return ans; } void Init () { f[0 ] = inf[0 ] = 1 ; for (int i = 1 ; i < 1e5 + 10 ; i++) { f[i] = f[i - 1 ] * i % mod; inf[i] = inf[i - 1 ] * qmi (i, mod - 2 , mod) % mod; } } int main () { cin >> n; Init (); while (n--) { int a, b; cin >> a >> b; cout << f[a] * inf[b] % mod * inf[a - b] % mod << '\n' ; } return 0 ; }
求组合数Ⅲ
(适合p较小)
给定 n 组询问,每组询问给定三个整数 \(a,b,p\) 其中 p是质数,请你输出\(C_a^b\mod p\) 的值。
\(1\leq n\leq 20,1\leq b\leq a \leq
10^{18},1\leq p\leq 10^{5}\)
lucas定理:\(C_a^b =
C_{\frac{a}{p}}^{\frac{b}{p}}C_{a\ mod\ p}^{b\ mod\ p}(mod\
p)\)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <bits/stdc++.h> using namespace std;typedef long long ll;ll a, b, p, n; ll qmi (ll a, ll b) { ll res = 1 ; while (b) { if (b & 1 ) res = res * a % p; a = a * a % p; b >>= 1 ; } return res; } ll C (ll a, ll b) { if (b > a) return 0 ; ll res = 1 ; for (int i = 1 , j = a; i <= b; i++, j--) { res = res * j % p; res = res * qmi (i, p - 2 ) % p; } return res; } ll lucas (ll a, ll b) { if (a < p && b <p) return C (a, b); return C (a % p, b % p) * lucas (a / p, b / p) % p; } int main () { cin >> n; while (n--) { cin >> a >> b >> p; cout << lucas (a, b) << '\n' ; } }
求组合数Ⅳ
输入a,b,求\(C_a^b\) ,其中\(1\leq b\leq a\leq 5000\)
因为没有mod,所以结果可能会很大,所以需要用高精度
但是如果直接用高精会超时,所以将\(C_a^b=\frac{a!}{b!(a-b)!}\) 中的\(a!\ b!\
(a-b)!^{-1}\) 用质因子进行表示,只进行上标的减法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <bits/stdc++.h> using namespace std;const int N = 5100 ;int prime[N], st[N], cnt, num[N];int a, b;void get_prime (int x) { for (int i = 2 ; i <= x; i++) { if (!st[i]) prime[cnt++] = i;; for (int j = 0 ; prime[j] <= x / i; j++) { st[i * prime[j]] = true ; if (i % prime[j] == 0 ) break ; } } } int count (int p, int n) { int res = 0 ; while (n) { res += n / p; n /= p; } return res; } vector<int > mul (const vector<int >& A, const int p) { if (p == 0 ) return {0 }; int t = 0 ; vector<int > res; for (int i = 0 ; i < A.size () || t > 0 ; i++) { if (i < A.size ()) t += A[i] * p; res.push_back (t % 10 ); t /= 10 ; } while (res.size () > 0 && res.back () == 0 ) res.pop_back (); return res; } int main () { cin >> a >> b; get_prime (a); for (int i = 0 ; i < cnt; i++) num[i] = count (prime[i], a) - count (prime[i], b) - count (prime[i], a - b); vector<int > res = {1 }; for (int i = 0 ; i < cnt; i++) for (int j = 0 ; j < num[i]; j++) res = mul (res, prime[i]); for (int i = res.size () - 1 ; i >= 0 ; i--) cout << res[i]; return 0 ; }