前言:我们平时遇到的组合数如果用杨辉三角型做的话,预处理的复杂度是 n 2 n^2 n2 ,遇到大一点的数据就会爆炸
我们怎么去优化呢
C
(
n
,
k
)
=
n
!
k
!
⋅
(
n
−
k
)
!
m
o
d
mod
C(n, k) = \frac{n!}{k! \cdot (n-k)!} \mod \text{mod}
C(n,k)=k!⋅(n−k)!n!modmod
答案太大我们会进行取模,那么我们就可以利用费马小定理
所以我们可以对我们的分母乘积进行逆元操作
但是我们的阶乘进行预处理
我们再来看一下下面这个题目,分析我们得知,只有我们选取的 1 的个数是大于等于 k /2 +1 的,才是有价值的
所以我们可以用组合数的方法进行
题目地址
有一个易错点,我们预处理的时候,阶乘的 a[ 0 ] = 1 , 否则会出错
#include<bits/stdc++.h>
using namespace std;
#define int long long
// 1 2 3
const int Mod = (int)1e9 + 7;
int n, k;
const int N = (int)2e5 + 5;
int a[N];
void ini() {
a[1] = 1; a[0] = 1;
for (int i = 2; i < N; i++) {
a[i] = (a[i - 1] * i) % Mod;
}
}
int qw(int x, int p) {
int t = 1;
while (p) {
if (p & 1) t = (t * x) % Mod;
x = (x * x) % Mod;
p >>= 1;
}
return t;
}
int C(int n, int k) {
if (n < k) return 0LL;
return (a[n] % Mod) * (qw(a[n - k] * a[k] % Mod, Mod - 2) % Mod) % Mod;
}
signed main() {
int t; ini();
//for (int i = 1; i <= 10; i++) cout << a[i] << endl;
//cout << qw(2, 2);
cin >> t;
while (t--) {
cin >> n >> k;
int one = 0;
for (int i = 1; i <= n; i++) {
int u; cin >> u;
if (u) one++;
}
int ans = 0;
for (int i = k / 2 + 1; i <= min(one, k); i++) {
int t = C(one, i) * C(n - one, (k - i)) % Mod;
ans = (ans + t) % Mod;
}
cout << ans << endl;
}
}