Contest Setting(动态规划,求方案数)

原题链接

题意

在这里插入图片描述
题目可以转化为, 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 i1种物品 j − 1 j-1 j1个一组时的所有方案得到,用前 i − 1 i-1 i1种物品 j − 1 j-1 j1个一组时的所有方案数*当前第 i i i个物品的数量,就是用第 i i i种物品 j j j个一组时的所有方案数,然后加上用 i − 1 i - 1 i1种物品, 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[i1][j1]w[i]+f[i1][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;
}

总结

还是练得不够多,思维跟不上啊。
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值