CF2182E New Year's Gifts 题解

题目传送门

2025 最后一天来写题解祭

思路

贪心。我们先将 \(val_i = z_i - y_i\)\(k = k - \sum y_i\),代表先给每个人买价值为 \(y_i\) 的礼物,还需要给 \(val_i\) 的价值就可以使第 \(i\) 个人高兴。

首先把礼盒用完肯定最优。从大到小依次枚举 \(val_i\),如果有礼盒可用,就用美丽值 \(\ge val_i\) 的最小美丽值的礼盒。这样更大的礼盒就可以用来满足其他的礼物。可以用 multiset 维护每一个礼盒,直接二分即可。对于剩下的礼盒,从小到大依次枚举 \(val_i\),只要钱还够用就买。

时间复杂度 \(\mathcal{O}(n \log m)\),可以通过本题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 5;

struct node
{
	int x, val;
} b[N];

int t, n, m, k;
int a[N];

bool cmp(node x, node y)
{
	return x.val > y.val;
}

bool cmp2(node x, node y)
{
	return x.val < y.val;
}

void solve()
{
	scanf("%lld%lld%lld", &n, &m, &k);
	for (int i = 1; i <= m; i++)
		scanf("%lld", &a[i]);
	for (int i = 1, y, z; i <= n; i++)
	{
		scanf("%lld%lld%lld", &b[i].x, &y, &z);
		b[i].val = z - y;
		k -= y;
	}
	sort(b + 1, b + n + 1, cmp);
	multiset<int> ms;
	for (int i = 1; i <= m; i++)
		ms.insert(a[i]);
	int ans = 0;
	for (int i = 1; i <= n; i++)
	{
		auto it = ms.lower_bound(b[i].x);
		if (it == ms.end()) continue;
		b[i].val = 2e9;
		ans++;
		ms.erase(it);
	}
	sort(b + 1, b + n + 1, cmp2);
	for (int i = 1; i <= n; i++)
	{
		if (b[i].val < 2e9 && k >= b[i].val)
		{
			ans++;
			k -= b[i].val;
		}
		else break;
	}
	printf("%lld\n", ans);
}

signed main()
{
	scanf("%lld", &t);
	while (t--) solve();
	return 0;
}
posted @ 2025-12-31 15:22  lucasincyber  阅读(1)  评论(0)    收藏  举报