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;
}