思维/STL(ICPC NE Regional 2019 A. Apprentice Learning Trajectory / codeforces1267A)

题目链接
题意:
现给你n个时间段,在每个时间段内可以花费t时间,获得一把剑。但是一个时间段只能造一把剑。最大化剑总和。
题解:
我们离散化后,遍历一遍区间,维护一个该区间段可以造的剑的集合。其中我们贪心选t最小的剑进行制作,这里可以用multiset。
例如样例1:

2
5 7 1
1 9 2

将区间离散化后,得到数组(这里值得注意的是,我们针对每个区间并不是离散[l, r],而是[l+t-1, r],因为直到l+t,该区间才真正的可以造剑,这里压入l+t-1,是因为我们要在上一个区间进行处理。):

2 , 5, 7, 9

这时,我们每个元素开一个vector,记录在遍历到该点时,应该从multiset删去和 添加的t值。在遍历完后,执行操作序列。维护multiset。另外multiset应该记录该能取该最小值的最左的左端点。期间,我们还要维护一个last指针,指向数组最后被覆盖的地方,我们下一次覆盖,就只能从这个点开始了。
下面是ac代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <bitset>
#include <array>
#include <cctype>
#include <time.h>

#pragma GCC optimize(2)

void read_f() { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); }
void fast_cin() { std::ios::sync_with_stdio(false); std::cin.tie(); }
void run_time() { std::cout << "ESC in : " << clock() * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl; }
template <typename T>
bool bacmp(const T & a, const T & b) { return a > b; }
template <typename T>
bool pecmp(const T & a, const T & b) { return a < b; }

#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr(x, y) (make_pair((x), (y)))
#define pb(x) push_back(x);
#define int ll
using namespace std;

const int N = 1e6 + 5;
const int inf = 0x3f3f3f3f;

struct Node
{
	ll l, r;
	ll sum;
} su[N];
ll lisan[N], cnt;
int getn(int x)
{
	return lower_bound(lisan + 1, lisan + cnt, x) - lisan;
}
multiset<pair<ll, ll> > q;
vector<pair<ll, ll> > v[N];
void add(int x)
{
	for (auto s : v[x])
	{
		if (s.first < 0)
			q.erase(q.lower_bound(make_pair(-s.first, s.second)));
		else
			q.insert(s);
	}
}
signed main()
{
	int n;
	scanf("%lld", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lld%lld%lld", &su[i].l, &su[i].r, &su[i].sum);
		lisan[++cnt] = su[i].l + su[i].sum-1;
		lisan[++cnt] = su[i].r;
	}
	sort(lisan + 1, lisan + cnt + 1);
	cnt = unique(lisan + 1, lisan + cnt + 1) - lisan;
	for (int i = 1; i <= n; i++)
	{
		v[getn(su[i].r)].push_back(make_pair(-su[i].sum, su[i].l));
		v[getn(su[i].l+su[i].sum-1)].push_back(make_pair(su[i].sum, su[i].l));
	}
	ll la = 0;
	add(1);
	ll ans = 0;
	for (int i = 2; i < cnt; i++)
	{
		if (q.size() == 0)
		{
			add(i);
			continue;
		}
		ll mil = (*q.begin()).second;
		ll c = lisan[i];
		ll s = max(mil, la);
		ll len = c - s;
		ll num;
		ans += (num = len / (*q.begin()).first);
		if (num != 0)
			la = s + num * (*q.begin()).first;
		add(i);
	}
	printf("%lld\n", ans);
	//run_time();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值