题解:B2164 组合数问题

题目要我们求从 \(1,2,\cdots,n\)\(n\) 个数中选择 \(m\) 个数的方案数,记作 \(C_n^m\)

首先观察边界情况。如果 \(m=0\),也就是从 \(n\) 个数中选择 \(0\) 个数,只能所有数都不选,方案数为 \(\bm{1}\)(注意不是 \(0\)),也就是说 \(C_n^0=1\)。如果 \(m=n\),也就是从 \(n\) 个数中选择 \(n\) 个数,只能所有数都选,方案数为 \(1\),也就是说 \(C_n^n=1\)

对于 \(1\le m\le n-1\) 的情况,答案不容易直接求得,因此考虑递推。考察 \(n\) 这个数是否被选上。如果被选上,只需在 \(1,2,\cdots,n-1\)\(n-1\) 个数中选择 \(m-1\) 个,方案数为 \(C_{n-1}^{m-1}\)。如果没被选,还需在 \(1,2,\cdots,n-1\)\(n-1\) 个数中选择 \(m\) 个,方案数为 \(C_{n-1}^m\)。根据加法原理,我们得到 \(C_n^m=C_{n-1}^{m-1}+C_{n-1}^m\)

\(O(n^2)\) 递推即可。

//By: OIer rui_er
#include <bits/stdc++.h>
using namespace std;

const int N = 5e3 + 5, mod = 1e9 + 7;

int n, m, C[N][N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m;
    for(int i = 0; i <= n; ++i) {
    	C[i][0] = C[i][i] = 1;
    	for(int j = 1; j <= i - 1; ++j) {
    		C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
    	}
    }
    cout << C[n][m] << endl;
    return 0;
}
posted @ 2026-01-08 10:16  rui_er  阅读(13)  评论(0)    收藏  举报