测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看

A23805. 金币收集

填空题 困难

题目描述

金币收集

题目描述

小 A 正在游玩收集金币的游戏。具体来说,在数轴上将会出现n枚金币,其中第i枚(1≤i≤n)金币将会在时刻ti出现在数轴上坐标为xi的位置。小 A 必须在时刻ti恰好位于坐标xi ,才可以获得第i枚金币。

游戏开始时为时刻 0,此时小 A 的坐标为0 。正常来说,小 A 可以按游戏机的按键在数轴上左右移动,但不幸的是游戏机的左方向键失灵了。小 A 每个时刻只能选择保持不动,或是向右移动一个单位。换言之,如果小 A 在时刻t的坐标为x,那么他在时刻t+1的坐标只能是x或是x+1二者之一,分别对应保持不动和向右移动。

小 A 想知道他最多能收集多少枚金币。你能帮他收集最多的金币吗?

输入格式

第一行,一个正整数n ,表示金币的数量。

接下来n行,每行两个正整数xi,ti,分别表示金币出现的坐标与时刻。

输出格式

输出一行,一个整数,表示小 A 最多能收集的金币数量。

样例

输入样例 1

3
1 6
3 7
2 4

输出样例 1

2

输入样例 2

4
1 1
2 2
1 3
2 4

输出样例 2

3

数据范围

对于40% 的测试点,保证1≤n≤8 。

对于另外30 % 的测试点,保证1≤n≤100 ,1≤xi≤100 ,1≤ti≤100 。

对于所有测试点,保证 1≤n≤105,1≤xi≤109 ,1≤ti≤109

参考答案

#include <algorithm> #include <cstdio> using namespace std; const int oo = 2e9; const int N = 1e5 + 5; int n; int x[N], t[N]; int p[N], f[N]; int mx; bool cmp(int a, int b) { if (x[a] != x[b]) return x[a] < x[b]; return t[a] < t[b]; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d", &x[i], &t[i]); t[i] -= x[i]; p[i] = i; f[i] = oo; } sort(p + 1, p + n + 1, cmp); mx = 0; f[0] = 0; for (int i = 1; i <= n; i++) { int l = 0, r = mx; int v = t[p[i]]; if (v < 0) continue; while (l < r) { int mid = (l + r) / 2 + 1; if (v < f[mid]) r = mid - 1; else l = mid; } mx = max(mx, r + 1); f[r + 1] = v; } printf("%d\n", mx); return 0; }
上一题 下一题