题意
n∗k n ∗ k 张卡片分给n个人,每人k张。第二行输入 n∗k n ∗ k 张卡片上面写的数字,第三行输入 n n 个人喜欢的数字,第四行输入k个数字,表示拿到 i i 张自己喜欢的卡片可以获得的快乐值。问所有人快乐值之和最大为多少?
思路
表示
i
i
张牌分给个人可以获得的快乐值(
i
i
张牌相同,这个人都喜欢这张牌)
状态转移方程为:
dp[i][j]=max(dp[i][j],dp[i−u][j−1]+h[u]),(1≤u≤min(i,k))
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
u
]
[
j
−
1
]
+
h
[
u
]
)
,
(
1
≤
u
≤
m
i
n
(
i
,
k
)
)
初始化
dp[i][1]=h[min(i,k)]
d
p
[
i
]
[
1
]
=
h
[
m
i
n
(
i
,
k
)
]
,因为一个人最多有k张卡片。
cnt[i]
c
n
t
[
i
]
表示数字
i
i
出现次数,表示喜欢数字
i
i
的人数。
然后枚举卡牌上的数字 ,累计
dp[cnt[i]][num[i]]
d
p
[
c
n
t
[
i
]
]
[
n
u
m
[
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
*/