HDU1521 排列组合(生成函数 背包)

题意

链接

Sol

可以用生成函数做,也可以用组合数做。

生成函数就是无脑算一下阶乘暴力背包,然后最后再乘上(M)的阶乘

组合数的方法就是用类似背包的转移,转移的时候考虑当前放的这几个的方案数即可

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 23;
inline int read() {
	char c = getchar(); int x = 0, f = 1;
	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * f;
}
int N, M = 22, v[MAXN];
long long f[MAXN][MAXN], C[MAXN][MAXN], fac[MAXN];
int main() {
	fac[0] = 1;
	for(int i = 1; i <= M; i++) fac[i] = i * fac[i - 1];
	for(int i = 0; i <= M; i++) {
		C[i][0] = C[i][i] = 1;
		for(int j = 1; j < i; j++) C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
	}
	while(scanf("%d %d", &N, &M) != EOF) {
		memset(f, 0, sizeof(f));
		f[0][0] = 1;
		for(int i = 1; i <= N; i++) {
			v[i] = read();
			for(int j = 0; j <= M; j++) {//now
				for(int k = 0; k <= j; k++) {//down
					if(j - k <= v[i]) {
 	 					f[i][j] += f[i - 1][k] * C[M - k][j - k];
						//cout << f[i][j] << '
';
					}	
				}
			}
		}
		cout << f[N][M] << '
';
	}
	return 0;
}