题目大意
给定一条数轴. 数轴上有(n)个点, 它们的初始位置给定, 移动速度也给定. 从0时刻开始, 所有点都从其初始位置按照其移动速度向数轴正方向移动. 这些点开始时可能是红色的, 也可能是黑色的, 这由你来决定, 也就是说这些点的颜色状态有(2^n)种; 假如某一时刻一个黑色的点与一个红色的点处于同一位置时, 则这个黑色的点会变成红色. 问有这(2^n)中状态中有多少满足最终所有点都变成红色.
(n le 10^5), 点的速度和位置(le 10^9)
题解
开始时我们默认所有点都是黑色的.
考虑把一个点变成红色会有什么样的影响: 首先是速度比他快并且起始位置在它后面的点会追上它, 因而变成红色; 同时速度比它慢且起始位置在它前面的点会被它追上, 因此也会变成红色; 但我们发现还有一些点也会变成红色: 比如说一个起始位置在后面的点追及后变成红色, 这之后可能继续追及一些点, 因此一些起始位置在这个点前面且速度比它快的点也有可能变成红色.
我们考虑把所有点按照其速度从小到大排序, 对于一个点我们把它变成红色, 那么我们找到最左边的一个起始位置大于等于它的点, 再找到最右边的起始位置小于等于它的点, 则我们发现这两个点之间的区间中, 所有点都能与之一起变成红色. 线段树优化DP即可.
这份代码目前还是WA的, 问题主要在于题目没有说清楚对于位置相同以及速度相同的点应该怎么处理.
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1; char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
using namespace std;
const int N = (int)2e5, MOD = (int)1e9 + 7;
int n;
int mn[N + 1], mx[N + 1];
struct point
{
int v, pos;
inline int operator <(const point &a) const {return v == a.v ? pos < a.pos : v < a.v;} // 注意速度相同的处理
}p[N + 1];
struct section
{
int L, R;
inline int operator <(const section &a) const {return R == a.R ? L < a.L : R < a.R;}
}sec[N + 1];
struct binaryIndexedTree
{
int a[N + 2];
inline binaryIndexedTree() {memset(a, 0, sizeof(a));}
inline void modify(int pos, int x)
{
for(int i = pos + 1; i <= n + 1; i += i & - i) a[i] = (a[i] + x) % MOD;
}
int query(int pos)
{
int res = 0;
for(int i = pos + 1; i; i -= i & - i) res = (res + a[i]) % MOD;
return res;
}
inline int query(int L, int R) {return (query(R) - query(L - 1) + MOD) % MOD;}
}BIT;
int main()
{
#ifndef ONLINE_JUDGE
freopen("incubator.in", "r", stdin);
freopen("incubator.out", "w", stdout);
#endif
using namespace Zeonfai;
n = getInt();
for(int i = 1; i <= n; ++ i) p[i].pos = getInt(), p[i].v = getInt();
sort(p + 1, p + n + 1);
for(int i = 1; i <= n; ++ i) mx[i] = i == 1 ? p[i].pos : max(mx[i - 1], p[i].pos);
for(int i = n; i; -- i) mn[i] = i == n ? p[i].pos : min(mn[i + 1], p[i].pos);
for(int i = 1; i <= n; ++ i)
{
int L = 1, R = i - 1, pos = i;
while(L <= R) if((mx[L + R >> 1] > p[i].pos) & (p[L + R >> 1].v != p[i].v)) {pos = L + R >> 1; R = (L + R >> 1) - 1;} else L = (L + R >> 1) + 1;
sec[i].L = pos;
L = i + 1; R = n; pos = i;
while(L <= R) if((mn[L + R >> 1] < p[i].pos) & (p[L + R >> 1].v != p[i].v)) {pos = L + R >> 1; L = (L + R >> 1) + 1;} else R = (L + R >> 1) - 1;
sec[i].R = pos;
}
sort(sec + 1, sec + n + 1);
BIT.modify(0, 1);
for(int i = 1; i <= n; ++ i)
BIT.modify(sec[i].R, BIT.query(sec[i].L - 1, sec[i].R));
printf("%d
", BIT.query(n, n));
}
/*
5
4 9
3 6
8 1
9 2
5 1
*/