持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情
E-生活大爆炸
题目描述
有n个男孩和m个女孩参加戏剧俱乐部。要制作一部戏剧《生活大爆炸》,他们需要选择一组由t个演员组成的剧组,其中包括不少于4名男孩和不少于1名女孩。有多少种方法可以组成一个小组?当然,只有剧团组成不同的变体才被认为是不同的。
输入描述:
一行包含三个整数n,m,t (4≤n≤30, 1≤m≤30, 5≤t≤n+m)
输出描述:
一行表示答案。
示例1
输入
5 2 5
输出
10
问题解析
这道题主要思路就是我们高中就学过的组合数计算。
男生有n人,女生有m人,需要组成总人数为t的队伍,其中男生人数不能少于4人,女生人数不能少于1人。
那么可能的排列组合就是:4个男生和t-4名女生,5个男生和t-5名女生,……,t-1名男生和1名女生。
对于第一个组合来说,就是n个男生中随机选出4个,搭配上m个女生中随机选出t-4个,即:C(n,4)*C(m,t-4)。其余的以此类推,把所有的组合数相加即可。
注意点1:由于结果可能很大,数据类型用int显然是不行的,这里要采用long long。
注意点2:有的同学算组合数C(a,b)时,是先计算a *(a-1) *(a-2) *…… *(1),再计算1 *2 *3 *…… *b,最后用两个结果相除。但是要注意,a最大可到30,如果傻傻的从1乘到30,哪怕是longlong也无法承受。(提问:longlong的范围是多少呢?不要求记住具体数,记住他是2的几次幂即可)。
这里我们涉及到组合数的递推公式:
也就是说,只要我们知道了C(n-1,m)和C(n-1,m-1),我们将他们相加便可以得到C(n,m)。以此类推。
为了方便,我们可以开一个二维数组C,将C(n,m)的结果存在C[n] [m]中,这样后续计算其它组合数时我们就省去了重复的计算,需要什么可以直接从数组中获取。
AC代码
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include <random>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<fstream>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#include<bitset>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#define endl '\n'
#define int ll
#define PI acos(-1)
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 4e5 + 50;
int C[70][70];
void init()
{
for (int i = 0; i <= 70; i++)
for (int j = 0; j <= i; j++) {
if (!j)
C[i][j] = 1;
else
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
void solve()
{
int n, m, t;
cin >> n >> m >> t;
init();
int res = 0;
for (int i = 4; i <= min(n, t - 1); i++)
{
res += C[n][i] * C[m][t - i];
}
cout << res;
}
signed main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}