BalticOI 2009 Day1 T2「Candy Machine」二维偏序+set

一.Problem

在糖果工厂中,有一台神秘的机器。它生产许多美味的糖果,每一个都与众不同。这个机器有一排输出槽,编号为 到 ,糖果加工完毕就会从里面出来。没有人真正知道它的工作原理,但是在每一次产品计划之前,它会打印一个列表告诉老板每个糖果会在何时从哪个槽出来。

现在,老板可以安装自动收集车在每个槽下移动,以收集掉落的糖果。当然,糖果不能掉到地上,不然就会碎裂。然而,安装自动收集车的成本极其高昂,老板想尽量少安装自动收集车。

写一个程序计算接住所有糖果需要的自动收集车的数量,它应当尽可能小。此外,你的程序还需要输出每颗糖果会被哪辆收集车接住。收集车每秒可以从一个槽移动到另一个相邻的槽。在生产过程开始前,每辆收集车可以移动到他应当收集的第一个糖果的位置。
1 ≤ n ≤ 100000 , 0 ≤ s i , t i ≤ 1000000000 1\leq n \leq 100000,0\leq s_i,t_i \leq 1000000000 1n100000,0si,ti1000000000
传送门

二.Solution

这道题目有点意思,其实就是推结论。
由题目我们可以知道若机器人能从 i i i j j j,那么 ∣ S j − S i ∣ |S_j-S_i| SjSi ≤ \leq T j − T i T_j-T_i TjTi
= > T i − T j ≤ S j − S i ≤ T j − T i =>T_i-T_j\leq S_j-S_i\leq T_j-T_i =>TiTjSjSiTjTi
= > { T i + S i ≤ T j + S i T i − S i ≤ T j − S j =>\left\{ \begin{aligned} T_i+S_i \leq T_j+S_i \\ T_i-S_i \leq T_j-S_j \end{aligned} \right. =>{Ti+SiTj+SiTiSiTjSj
于是就可以发现这是一个以 ( T i + S i , T i − S i ) (T_i+S_i,T_i-S_i) (Ti+Si,TiSi)为关键字的二维偏序。
什么是二位偏序呢?

我的理解就是要以两个关键字排序,那么实现就是先以一个关键字排序,再维护另一个关键字,这可以用树状数组实现。

然后考虑这道题目先按第一个关键字排序,那么就要找以第二个关键字为标准的最少有多少个上升子序列。
于是我们每次贪心地取 T j − S j ≤ T i − S i T_j-S_j\leq T_i-S_i TjSjTiSi T j − S j T_j-S_j TjSj最大的 j j j,这两个用同一个机器人去接,将 j j j更新为 i i i,如果找不到一个 j j j使得 T j − S j ≤ T i − S i T_j-S_j\leq T_i-S_i TjSjTiSi,就需要用另一个机器人去接。

这个过程需要用 s e t set set实现,却有用数组实现的大佬(我自己就是),这里介绍几种 s e t set set的基本操作(set常数大的一批,因为它自动排序去重):

  • 首先有一些基本的操作,比如:
    . i n s e r t ( s t h ) .insert(sth) .insert(sth)插入
    . e r a s e ( s t h ) .erase(sth) .erase(sth)删除
    . c o u n t ( s t h ) .count(sth) .count(sth)某个元素的个数
    . b e g i n ( ) .begin() .begin()返回第一个元素
    . e n d ( ) .end() .end()返回最后一个元素
    . c l e a r ( ) .clear() .clear()清空
    . e m p t y ( ) .empty() .empty()判断是否为空
    . s i z e ( ) .size() .size()返回元素个数
  • 然后有一个进阶操作,注意要先写出迭代器set<>::iterator it = S.操作,<>内写你定义的类型,这里的操作有:
    ①.lower_bound(sth)返回第一个大于或等于sth的迭代器位置
    ②.upper_bound(sth)返回第一个大于sth的迭代器位置

三.Code

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

#define M 100005

struct node {
	int s, t, id;
	friend bool operator < (node a, node b){
		return a.t - a.s == b.t - b.s ? (a.t + a.s) < (b.t + b.s) : (a.t - a.s < b.t - b.s);
	}
}a[M];
int n, cnt;
set <node> ans;

template <class T> inline T read (T x){
	x = 0; T f = 1; char c = getchar ();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar ();}
	while (c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar ();}
	return x * f;
}
bool cmp (node a, node b){
	return a.t + a.s == b.t + b.s ? (a.t - a.s) < (b.t - b.s) : (a.t + a.s < b.t + b.s);
}
signed main (){
	freopen ("candy.in", "r", stdin);
	freopen ("candy.out", "w", stdout);
	n = read (1);
	for (int i = 1; i <= n; i ++){
		a[i].s = read (1), a[i].t = read (1);
		//printf ("%d\n", a[i].t - a[i].s);
	}
	sort (a + 1, a + 1 + n, cmp);
	for (int i = 1; i <= n; i ++){
		set<node>::iterator it = ans.upper_bound (a[i]);
		if (it == ans.begin ())
			a[i].id = ++ cnt;
		else
			it --, a[i].id = it -> id, ans.erase (it);
		ans.insert (a[i]);
	}
	printf ("%d\n", cnt);
	for (int i = 1; i <= n; i ++){
		printf ("%d %d %d\n", a[i].s, a[i].t, a[i].id);
	}
	return 0;
}

Thanks!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值