Contest Setting(dp)

 A group of contest writers have written n problems and want to use k of them in an upcoming contest. Each problem has a difficulty level. A contest is valid if all of its k problems have different difficulty levels. Compute how many distinct valid contests the contest writers can produce. Two contests are distinct if and only if there exists some problem present in one contest but not present in the other. Print the result modulo 998,244,353.

Input:

The first line of input contains two space-separated integers n and k (1 ≤ k ≤ n ≤ 1000). The next line contains n space-separated integers representing the difficulty levels. The difficulty levels are between 1 and 109 (inclusive).

Output:

Print the number of distinct contests possible, modulo 998,244,353.

Sample Input :

5 2

1 2 3 4 5

5 2

1 1 1 2 2 6

12 5

3 1 4 1 5 9 2 6 5 3 5 8

Output :

10

6

316

题目意思:

给你n到题目的难度水平,让你从中选取k道题来组成一个contest,要求这k道题难度没有相同的,让你求方案数。

Solution:

刚开始一直是往组合数方面去想,后来发现数据量不算大,就尝试往二维的dp方向去想(比赛结束也没想出来。。。)

当然,数据的范围很广,我们要把它缩小一下,因为我们并不需要具体的难度值,我们只需要相同难度的题目的个数。

我用val数组来存放不同难度题目的数量。

dp[i][j]代表前i个数中挑出j个的方案数,那么就可以这样状态转移:

dp[i][j] = dp[i - 1][j - 1] * val[i] + dp[i - 1][j];

也就是前i - 1个数挑出j个的方案数(这是之前就求出来的,相当于继承了下来),dp[i - 1][j - 1] * val[i] 这个是新增加的一道题目所带来的方案书的增加量。说的通俗一点就是:现在的 = 之前的 + 新增加的。应该能理解吧。。

最后还有一个dp数组初始化的问题(如果你很擅长处理这种小问题,下来的没必要看了),你可以观察边界状态所需要的前驱状态从而来初始化,就拿这个代码来说,我的内层for循环是从1开始跑的,那么我需要的是dp[i - 1][0]和dp[i - 1][1],那么你就必须保证每次进行内层循环的时候所需要的这两个状态是正确的,你可以在开始之前统一初始化,也可以在开始内层循环之前初始化,如果不知道如何初始化,还可以把样例拿过来参考。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int mod = 998244353;
int a[1010];
ll val[1010];
ll dp[1010][1010];


int main()
{
//	freopen("in.txt", "r", stdin);
	int n, k;
	cin >> n >> k;
	for(int i = 1; i <= n; ++ i)
	{
		scanf("%d", &a[i]);
	}
	sort(a + 1, a + 1 + n);
	int cnt = 1;
	int top = 1;
	for(int i = 2; i <= n; ++ i)
	{
		if(a[i] == a[i - 1])
			cnt++;
		else 
		{
			val[top++] = cnt;
			cnt = 1;
		}
	}
	val[top++] = cnt;
	memset(dp, 0, sizeof(dp));
	for(int i = 0; i <= 1000; ++ i)
		dp[i][0] = 1;
	for(int i = 1; i < top; ++ i)
	{
		//dp[i][1] = val[i] + dp[i - 1][1];
		for(int j = 1; j <= k; ++ j)
		{
			dp[i][j] = (dp[i - 1][j - 1] * val[i] % mod + dp[i - 1][j]) % mod;
		}
	}
	cout << dp[top - 1][k] << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/84643172