Luogu 题解 P2638 【安全系统】

组合数学


题目

题意:有两种不同的球,放入n个箱子中,箱子可以放,也可以不放
分析:这是一种经典组合题,即往盒子中装球,我们由小学奥数可以得出结论:
( ext{ans = }sum^{a}_{i = 0} sum^{b}_{j = 0} ext{C[i + n - 1][n - 1] C[j + n - 1][n - 1]})

我们得到公式后,还需要一个高效计算组合数的算法,这是我们便想到了杨氏三角:
众所周知

        1
       1 1
      1 2 1
     1 3 3 1
    1 4 6 4 1
    .........

于是我们得到了一个公式:
C[i][j] = C[i - 1][j - 1] + C[i - 1][j]
其中当j == 0 || j == i时,C[i][j] = 1

得到了一段预处理组合数的代码:

void Pre_Work() {
	for(int i = 0; i <= 50; i ++) con[i][0] = con[i][i] = 1;
	for(int i = 2; i <= 50; i ++)
		for(int j = 1; j <= i; j ++)
			con[i][j] = con[i - 1][j] + con[i - 1][j - 1];
}
#include <cstdio>
#include <iostream>
#define int unsigned long long
//注意要用ull
using namespace std;
int read() {
	int w = 1,res = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') w = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') res = res * 10 + ch - '0', ch = getchar();
	return w * res;
}
int con[100][100], ans;
void Pre_Work() {
	for(int i = 0; i <= 50; i ++) con[i][0] = con[i][i] = 1;
	for(int i = 2; i <= 50; i ++)
		for(int j = 1; j <= i; j ++)
			con[i][j] = con[i - 1][j] + con[i - 1][j - 1];
}
signed main() {
	int n = read(), a = read(), b = read();
	Pre_Work();
	for(int i = 0; i <= a; i ++)
		for(int j = 0; j <= b; j ++)
			ans += con[i + n - 1][n - 1] * con[j + n - 1][n - 1];
	cout << ans;
	return 0;
}
原文地址:https://www.cnblogs.com/Wuzhuoming-sirenboke/p/14064372.html