你要举办一场生日派对。派对有
n
n
n个人,每个人都有一个数字
k
i
k_i
ki。超市有
m
m
m件礼物,购买每件礼物需要花费$$c_j(c_1<c_2<…<c_m)
,
且
每
个
礼
物
只
有
一
件
。
你
要
给
这
,且每个礼物只有一件。你要给这
,且每个礼物只有一件。你要给这n
个
人
发
东
西
,
对
于
第
个人发东西,对于第
个人发东西,对于第i$个人,你有两种选择:
1. 给第
i
i
i个人发礼物,那么给这个人的礼物要求
j
<
=
k
i
j<=k_i
j<=ki,即礼物的编号不能超过这个人的数字
k
i
k_i
ki;
2. 直接给这个人$$c_{k_i}$.
现在要你求出最小的花费。
思路:
按花费从小到大依次分配礼物。假设现在要分配的礼物的编号是
c
u
r
cur
cur,利用贪心的思想,当
c
u
r
<
=
k
i
cur<=k_i
cur<=ki时,依次将花费最小的礼物分给
k
i
k_i
ki最大的人;当
c
u
r
>
k
i
cur>k_i
cur>ki时,直接给这位朋友$$c_{k_i}$。
原因如下:当
c
u
r
<
=
k
i
cur<=k_i
cur<=ki时,有
c
c
u
r
<
=
c
k
i
c_{cur}<=c_{k_i}
ccur<=cki;当
c
u
r
>
k
i
cur>k_i
cur>ki时,有
c
k
i
<
c
c
u
r
c_{k_i}<c_{cur}
cki<ccur,每次都取两者中较小的。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
const int Maxn = 300005;
int a[Maxn], b[Maxn];
void solve() {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", a + i);
}
for (int i = 1; i <= m; i++) {
scanf("%d", b + i);
}
std::sort(a + 1, a + n + 1);
ll ans = 0;
int cur = 1;
for (int i = n; i > 0; i--) {
if (a[i] > cur) {
ans += b[cur++];
} else {
ans += b[a[i]];
}
}
printf("%lld\n", ans);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}