洛谷P11250 [GESP202409 八级] 手套配对 题解

题目传送门。

非常简单的组合数学题。

首先从 \(n\) 对手套中恰好选出 \(k\) 对手套的方案数为 \(C_n^k\),然后由于我们要取出 \(m\) 只手套,那么取了 \(k\) 对手套后还要取 \(m-2k\) 只手套,我们得保证后面取的这 \(m-2k\) 对手套配不出一对手套,根据鸽笼原理,在最坏情况下,我们从 \(n-k\) 对手套中选不超过 \(n-k\) 只手套,是选不出一对手套的,于是我们就按照这种情况算,于是我们得出了 \(C_{n-k}^{m-2k}\),然后由于我们会选到一对手套的左手或右手,所以我们还要乘上 \(2^{m-2k}\),所以最后的答案为 \(C_n^k \times C_{n-k}^{m-2k} \times 2^{m-2k}\)

至于什么是鸽笼原理,就是比如说班上如果有超过 \(12\) 个人一定有两个人出生月份相同,这就是鸽笼原理,证明也很简单,这里就不多说了。

然后由于这道题 \(1 \le n \le 1000\),直接使用组合数公式 \(C_n^m = C_{n-1}^m+C_{n-1}^{m-1}\),两遍 for 循环就能解决。

哦,当 \(m \le 2k\) 时,无解,因为无法选出 \(k\) 对手套,还有,就是当 \(m-2k>n-k\) 时,根据鸽笼原理很容易得出此时也是无解,配出的手套数量一定大于 \(k\)。但是这个无解情况是不用判断的,因为我们求组合数的数组 \(c\) 是全局数组,系统一开始会全部初始化为 \(0\),这样子当 \(m-2k>n-k\) 时,算出的组合数一定是 \(0\)\(0\) 乘任何数都等于 \(0\),所以不用判断这种情况。

十年 OI 一场空,不开 long long 见祖宗。

计算二的次幂时请使用快速幂或者预处理,不要使用左移或者 pow 函数,否则就会见祖宗!

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int mod = 1e9+7;
const int N = 2e3+5;
int c[N][N],f[N];
signed main()
{
 	int _;
	scanf("%lld",&_);
	for(int i = 0;i<=N-5;i++)
	{
		for(int j = 0;j<=i;j++)
		{
			c[i][j] = !j?1:(c[i-1][j]+c[i-1][j-1])%mod;
		}
	}
	f[0] = 1;
	for(int i = 1;i<=N-5;i++)
	{
		f[i] = f[i-1]*2%mod;
	}
	while(_--)
	{
		int n,m,k;
		scanf("%lld %lld %lld",&n,&m,&k);
		if(m<2*k)
		{
			printf("0\n");
			continue;
		}
		printf("%lld\n",c[n][k]*c[n-k][m-2*k]%mod*f[m-2*k]%mod);
	}
    return 0;
}
posted @ 2025-02-20 18:05  林晋堃  阅读(308)  评论(0)    收藏  举报