题目链接:
传送门
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N = 1010;
const ll p = 1000000007;
ll t, n, m, r, ca;
ll fact[N], infact[N], d[N];
//快速幂模板
ll qmul(ll a, ll k) {
ll res = 1;
while (k) {
if (k & 1) res = res * a % p;
a = (ll)a * a % p;
k >>= 1;
}
return res;
}
int main() {
fact[0] = infact[0] = 1;
d[0] = 1;
d[1] = 0;
//所有数的阶乘及其逆元打表
for (ll i = 1; i < N; i++) {
fact[i] = fact[i - 1] * i % p;
infact[i] = infact[i - 1] * qmul(i, p - 2) % p;
}
//n个数全错排数的打表
for (ll i = 2; i < N; i++) {
d[i] = (d[i - 1] + d[i - 2]) % p * (i - 1) % p;
}
scanf("%lld", &t);
while(t--) {
scanf("%lld%lld%lld", &n, &m, &r);
ll ans = 0;
ll q = n - m;
//枚举所有错排的情况
for (ll i = 0; i <= q; i++) {
ll c = fact[q] * infact[i] % p * infact[q - i] % p;
ans = (ans + c * d[n - r - i]) % p;
}
//最后乘上固定不动的组合数
ans = ans * (fact[m] * infact[r] % p * infact[m - r] % p) % p;
printf("Case %lld: %lld\n", ++ca, ans);
}
}
这道题是组合数加上全错排的一个应用
首先打表求出所有数字的阶乘及其阶乘的逆元,以方便后面求组合数
接着打表求出n个数字的全错排数
最后枚举所有错排情况,即m - k个必须错排,后面n - m个数可错排,可不错排。