题意
n∗kn∗k张卡片分给n个人,每人k张。第二行输入n∗kn∗k张卡片上面写的数字,第三行输入nn个人喜欢的数字,第四行输入k个数字,表示拿到ii张自己喜欢的卡片可以获得的快乐值。问所有人快乐值之和最大为多少?
思路
表示ii张牌分给个人可以获得的快乐值(ii张牌相同,这个人都喜欢这张牌)
状态转移方程为:dp[i][j]=max(dp[i][j],dp[i−u][j−1]+h[u]),(1≤u≤min(i,k))dp[i][j]=max(dp[i][j],dp[i−u][j−1]+h[u]),(1≤u≤min(i,k))
初始化dp[i][1]=h[min(i,k)]dp[i][1]=h[min(i,k)],因为一个人最多有k张卡片。
cnt[i]cnt[i] 表示数字 ii出现次数,表示喜欢数字 ii 的人数。
然后枚举卡牌上的数字 ,累计dp[cnt[i]][num[i]]dp[cnt[i]][num[i]]就是答案。
#include <bits/stdc++.h>
using namespace std;
int n, k, c[5005], f[505], h[15];
int cnt[100005], num[100005], dp[5005][505];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n*k; i++) scanf("%d", &c[i]), cnt[c[i]]++;
for (int i = 0; i < n; i++) scanf("%d", &f[i]), num[f[i]]++;
for (int i = 1; i <= k; i++) scanf("%d", &h[i]);
for (int i = 1; i <= n*k; i++)
{
dp[i][1] = h[min(i, k)];//i张牌分给1个人
for (int j = 2; j <= n; j++)
{
for (int u = 1; u <= min(i, k); u++)
{
dp[i][j] = max(dp[i][j], dp[i-u][j-1]+h[u]);
}
}
}
long long ans = 0;
for (int i = 0; i <= 1e5; i++) if (num[i])
ans += dp[cnt[i]][num[i]];
printf("%lld\n", ans);
return 0;
}
/*
4 3
1 3 2 8 5 5 8 2 2 8 5 2
1 2 2 5
2 6 7
*/