[AT2383] [AGC015 E] Mr.Aoki Incubator

43 篇文章 1 订阅
19 篇文章 0 订阅
洛谷传送门
Atcoder传送门

题目大意

数轴上有 N N N个点,每个点初始时在位置 X i X_i Xi,以 V i V_i Vi的速度向数轴正方向前进

初始时刻,你可以选择一些点为其染色,之后的行走过程中,染色的点会将其碰到的所有点都染上色,之后被染上色的点亦是如此

在所有 2 N 2^N 2N种初始染色方案中,问有多少种初始染色方案,能使得最终所有的点都被染色?答案对 1 0 9 + 7 10^9+7 109+7取模

输入输出格式

输入格式

第一行一个正整数 N N N

以下 N ​ N​ N行, 每行两个正整数 X i , V i ​ X_i,V_i​ Xi,Vi

输出格式

输出一个正整数, 表示方案数对 1 0 9 + 7 10^9+7 109+7取模的结果。

输入输出样例

输入样例#1:
3
2 5
6 1
3 7
输出样例#1:
6
输入样例#2:
4
3 7
2 9
8 16
10 8
输出样例#2:
9

解题分析

考虑点 a a a被染色, 然后导致点 b b b被染色的情况:

  • b b b速度比 a a a慢, 但在点 a a a前面。
  • b b b速度比 a a a快, 但在点 a a a后面。
  • b b b速度比 a a a慢, 在 a a a后面, 但存在点 c c c比点 b b b速度慢, 在 a a a前面。
  • b b b速度比 a a a快, 在 a a a前面, 但存在点 c c c比点 b b b速度快, 在 a a a后面。

然后我们观察第3、 4点, 发现只需要按速度把所有点排序,找到比 i i i速度慢且在 i i i前面的第一个点 l l l, 比 i i i速度快且在 i i i后面的最后一个点 r r r, 那么对于每个点 i i i染色都会导致 [ l , r ] [l,r] [l,r]的点全部染色。

然后一个数据结构维护 d p dp dp就好了。

代码如下:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <climits>
#include <set>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 200500
#define gc getchar()
#define ls (now << 1)
#define rs (now << 1 | 1)
#define ll long long 
#define MOD 1000000007
#define lbt(i) ((i) & (-(i)))
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
int n, bd;
int tree[MX];
struct INFO {int pos, spd;} dat[MX];
struct Seg {int lb, rb;} seg[MX];
IN bool operator < (const INFO &x, const INFO &y) {return x.spd < y.spd;}
IN bool operator < (const Seg &x, const Seg &y) {return x.rb == y.rb ? x.lb < y.lb : x.rb < y.rb;}
namespace SGT1
{
	int mn[MX << 2], mx[MX << 2];
	IN void pushup(R int now)
	{
		mn[now] = min(mn[ls], mn[rs]);
		mx[now] = max(mx[ls], mx[rs]);
	}
	void build (R int now, R int lef, R int rig)
	{
		if (lef == rig) return mn[now] = mx[now] = dat[lef].pos, void();
		int mid = lef + rig >> 1;
		build(ls, lef, mid), build(rs, mid + 1, rig);
		pushup(now);
	}
	int qmin(R int now, R int lef, R int rig, R int lb, R int rb)
	{
		if (lef >= lb && rig <= rb) return mn[now];
		int mid = lef + rig >> 1, ret = INT_MAX;
		if (lb <= mid) ret = qmin(ls, lef, mid, lb, rb);
		if (rb >  mid) ret = min(ret, qmin(rs, mid + 1, rig, lb, rb));
		return ret;
	}
	int qmax(R int now, R int lef, R int rig, R int lb, R int rb)
	{
		if (lef >= lb && rig <= rb) return mx[now];
		int mid = lef + rig >> 1, ret = -INT_MAX;
		if (lb <= mid) ret = qmax(ls, lef, mid, lb, rb);
		if (rb >  mid) ret = max(ret, qmax(rs, mid + 1, rig, lb, rb));
		return ret;
	}
	int qpos(R int now, R int lef, R int rig, R int lb, R int rb, R int tar, R bool typ)
	{
		if (lef == rig) return lef;
		int mid = lef + rig >> 1;
		if (!typ)//to query the most left point with pos > tar
		{
			if (mx[ls] >= tar) return qpos(ls, lef, mid, lb, rb, tar, typ);
			else return qpos(rs, mid + 1, rig, lb, rb, tar, typ);
		}
		else
		{
			if (mn[rs] <= tar) return qpos(rs, mid + 1, rig, lb, rb, tar, typ);
			else return qpos(ls, lef, mid, lb, rb, tar, typ);
		}
	}
}
IN void add(R int pos, R int v)
{for (; pos <= bd; pos += lbt(pos)) (tree[pos] += v) %= MOD;}
IN int qpfix(R int pos)
{
	int ret = 0;
	for (; pos; pos -= lbt(pos)) (ret += tree[pos]) %= MOD;
	return ret;
}
IN int query(R int lb, R int rb) {return (qpfix(rb) - qpfix(lb - 1) + MOD) % MOD;}
int main(void)
{
	in(n); bd = n + 1;
	for (R int i = 1; i <= n; ++i) in(dat[i].pos), in(dat[i].spd);
	std::sort(dat + 1, dat + 1 + n);
	SGT1::build(1, 1, n);
	for (R int i = 1; i <= n; ++i)
	{
		seg[i].lb = SGT1::qpos(1, 1, n, 1, i, dat[i].pos, 0);
		seg[i].rb = SGT1::qpos(1, 1, n, i, n, dat[i].pos, 1);
	}
	std::sort(seg + 1, seg + 1 + n);
	add(1, 1);
	for (R int i = 1; i <= n; ++i) seg[i].lb++, seg[i].rb++, add(seg[i].rb, query(seg[i].lb - 1, seg[i].rb));
	printf("%d", query(n + 1, n + 1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值