组合数问题
# 组合数性质
# 组合数为奇数的情况
组合数为奇数,当且仅当是的子码(submask)(也就是说,)
证明如下:
,因此要判断的奇偶性,只需要知道的素数分解中个数
设中的个数分别为,显然有,当且仅当时组合数为奇数
由勒让德定理,可知
定义函数,有
令,显然有
因此,,同理,
当时,即
由数学归纳法可以证明:,当且仅当时等号成立
参考:
- https://blog.csdn.net/netown_ethereal/article/details/35234873
- https://blog.csdn.net/weixin_40859716/article/details/84647291
# 组合数求法
# 卢卡斯定理(求余组合数)
(均为板除)
编写程序时,使用下面这条等式:
# 证明
对于质数,对于有
再由二项式定理定理得
由二项式定理可知
对于求,可以转化为求展开式中的系数。
令
则
因此
# 例题 洛谷P3807
题意:给定,求
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod;
ll inv(ll base){
ll ret = 1, t = mod - 2;
for(;t; t>>=1){
if(t & 1) ret = ret * base % mod;
base = base * base % mod;
}
return ret;
}
// 暴力求组合数,有优化空间
ll Comb(ll n, ll m){
if(n < m) return 0;
if(n - m < m) m = n - m;
ll denom = 1, numer = 1;
for(int i=0; i<m; i++){
numer = numer * (n - i) % mod;
denom = denom * (i + 1) % mod;
}
return numer * inv(denom) % mod;
}
ll Lucas(ll n, ll m){
if(m == 0) return 1;
return Lucas(n / mod, m / mod) * Comb(n % mod, m % mod) % mod;
}
signed main(){
int t; cin >> t;
while(t--) {
ll a, b;
cin >> a >> b >> mod;
cout << Lucas(a + b, a) << '\n';
}
}
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
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
上次更新: 2021/02/24, 03:37:30