「中山纪中集训省选组D1T1」最大收益 贪心

题目描述

给出N件单位时间任务,对于第i件任务,如果要完成该任务,需要占用[Si,Ti]间的某个时刻,且完成后会有Vi的收益。求最大收益。

澄清:一个时刻只能做一件任务,做一个任务也只需要一个时刻。

输入格式

第一行一个整数N,表示可供选择的任务个数。

接下来的第二到第N+1行,每行三个数,其中第i+1行依次为Si,Ti,Vi

输出格式

输出最大收益

样例

样例输入1

2
1 1 1
1 1 2

样例输出1

2

样例输入2

3
1 1 5
2 2 3
1 2 4

样例输出2

9

样例输入3

6
1 2 10
2 3 10
3 4 10
4 5 10
1 1 5
5 5 6

样例输出3

46

数据范围

在所有数据中,N50001Si1081Vi108

题解

我又诈尸了。
来到中山纪中集训,省选组的题目第一天就这么神(集训队的题能不神么)……真是Orz,咱全场几乎爆零成功垫底。

回到题目,直接说正解。考虑将任务的价值从大到小排序,假设我们已经安排好了前i1个任务,其中要完成的任务集合是S。如果要完成第i个任务会导致原来处于S的任务中的一个无法完成,那么我们果断放弃第i个任务(因为如果换做完成i,并没有腾出更多时间,但却丢失了更多价值),否则我们没有理由不完成i个任务。

那么我们只需要完成一步就好了,那就是判断将任务i加入集合S后是否能让所有任务都能找到时间做。这个东西我们可以用一个简单粗暴的方法,每次从任务i的起始时间开始找,如果这个时间没有被占领,那么占领,结束。否则找到占领该时间的任务,记作j。此时就存在一个选择,到底是让i去后面找时间还是让j找?显然,能拖得更久的任务去尝试更好,也就是结束时间更晚的那一个去找。就这样递归下去,直到不冲突或者超出任务的结束时间为止(超出了当然就得放弃任务了……)。每次最多遇到i1次冲突(因为最多也只有i1个任务),判断一次的复杂度是O(n)的。

这里有一个空间上的优化。其实有用的时间其实并不多,我们将他们记为“活跃点”。我们从每个任务的起始时间开始找,找到第一个空位,就将它加入“活跃点”,显然只考虑活跃点的情况下仍然可以达到最优,这样可以把空间也优化到O(n)(然而代价是时间复杂度有了离散化时的log)。

Code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 5005
#define ll long long
int n;
struct node
{
	int s, t, v;
}S[N];
bool cmp1(node a, node b){return a.s < b.s;}
bool cmp2(node a, node b){return a.v > b.v;}
int data[N], plc[N];
int Find(int x, int p)
{
	if (p > S[x].t)
		return 0;
	if (!plc[p])
	{
		plc[p] = x;
		return 1;
	}
	if (S[plc[p]].t < S[x].t)
		return Find(x, p + 1);
	if (Find(plc[p], p + 1))
	{
		plc[p] = x;
		return 1;
	}
	return 0;
}
int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d%d%d", &S[i].s, &S[i].t, &S[i].v);
	sort(S + 1, S + n + 1, cmp1);
	for (int i = 1; i <= n; i++)
		data[i] = max(data[i - 1] + 1, S[i].s);
	for (int i = 1; i <= n; i++)
	{
		S[i].s = lower_bound(data + 1, data + n + 1, S[i].s) - data;
		S[i].t = upper_bound(data + 1, data + n + 1, S[i].t) - data - 1;
	}
	sort(S + 1, S + n + 1, cmp2);
	ll ans = 0;
	for (int i = 1; i <= n; i++)
		if (Find(i, S[i].s))
			ans += S[i].v;
	printf("%lld\n", ans);
}
posted @   ModestStarlight  阅读(249)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示