赞
踩
题目可以转化为,
n
n
n种不同的物品,每种有
w
[
i
]
w[i]
w[i]个,问用这些物品中选k种,能有多少种组合方式,每一种组合中的物品必须各不相同,问总共可以有多少种组合方案。
定义
f
[
i
]
[
j
]
f[i][j]
f[i][j]为用前i种物品,每
j
j
j个一组的所有组合方案数。
首先,因为要求的是组合方式,所以,应该用,乘法,既然要用乘法,那么初始化,肯定得是1,也可以理解为所有物品一个都不选时为一种方案。
然后我们通过推导得出用前i种物品 j j j个一组时可以由用前 i − 1 i-1 i−1种物品 j − 1 j-1 j−1个一组时的所有方案得到,用前 i − 1 i-1 i−1种物品 j − 1 j-1 j−1个一组时的所有方案数*当前第 i i i个物品的数量,就是用第 i i i种物品 j j j个一组时的所有方案数,然后加上用 i − 1 i - 1 i−1种物品, j j j个一组时的所有方案数可以得到 用前i种物品j个一组时的所有方案数。得出状态转移方程 f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] ∗ w [ i ] + f [ i − 1 ] [ j ] f[i][j] = f[i - 1][j - 1] * w[i] + f[i - 1][j] f[i][j]=f[i−1][j−1]∗w[i]+f[i−1][j]
如果有所遗忘那就看看我的手记吧
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1005, mod = 998244353; int a[N] ; int f[N][N]; int n, k; int cnt = 1; map<int, int> res; int w[N]; signed main() { cin >> n >> k; for (int i = 1; i <= n; i ++ ) { cin >> a[i]; res[a[i]] ++; } for (auto i : res) { w[cnt ++ ] = i.second; } cnt --; // for (int i = 1; i <= cnt; i ++ ) cout << w[i] << " "; //初始化应从0开始 for (int i = 0; i <= cnt; i ++ ) f[i][0] = 1; for (int i = 1; i <= cnt; i ++ ) { for (int j = 1; j <= k; j ++ ) { f[i][j] = f[i - 1][j - 1] * w[i] % mod + f[i - 1][j]; f[i][j] %= mod; } // for (int j = 1; j <= k; j ++ ) // { // cout << f[i][j] << " "; // } // cout << endl; } cout << f[cnt][k] % mod << endl; return 0; }
还是练得不够多,思维跟不上啊。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。