题目大意
Farmer John 的 N 头奶牛 ( 1 ≤ N ≤ 1e5 ) 正在一条长度无限的跑道上慢跑,每头奶牛都有一个不同的开始位置,以及不同的跑步速度。
为了方便奶牛们互相超越,整个跑道被分成了若干条赛道。在同一时刻,不可能有在同一条赛道上的两头奶牛占据相同的位置。
现在奶牛们要跑 T 分钟,在跑步过程中,他们不会改变自己所在的赛道和自己跑步的速度。FJ想要知道,为了奶牛间不会发生冲突,他需要至少准备多少条赛道。
输入格式:第一行包括两个整数 N 和 T 。接下来 N 行,每行两个整数 pi 和 vi ( pi,vi ≤ 1e9 )分别代表奶牛的初始位置和速度。
输出格式:一个整数,代表最少需要的跑道数目。
题目分析
考虑什么情况下两头奶牛 i , j 不能同时处在一条赛道上。
假设 i 的起始位置比 j 小,那么当 i 的结束位置>= j 的结束位置时,i 和 j 就不能同时处在一条跑道上了。
因为牛的起始位置 Si 读入时是从小到大的,所以假设读入到 i 牛, 我们可以算出它的结束位置 Ti,
若之前的某头牛 j (之前的牛起点都比 Si 小)的结束位置 Tj 比 Ti 要小,那么就说明牛 i 和 牛 j 可以处在同一条跑道上。
贪心地想,我们要让 Ti 与 Tj 的距离差尽量小,这样才能保证跑道被“充分利用”。
所以,每读入一头牛 i ,我们就把它的结束位置 Ti 与前面的牛比较,找到一个最大的比 Ti 小的 Tj,把 Ti 接到 Tj 后面;若找不到,就把他存下来。
最后存下来的个数即需要跑道的最小个数。
哎?这不就是最长不下降子序列(LIS)吗?所以直接用 数组+二分查找 在O(N logN)时间内实现即可。
(USACO上求LIS的方法很简短,值得学习。)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 int n; 6 ll t; 7 vector<ll> a; 8 int main(){ 9 scanf("%d%lld",&n,&t); 10 for(int i=1;i<=n;++i){ 11 ll pos,v; 12 scanf("%lld%lld",&pos,&v); 13 pos=-(pos+v*t); 14 if(a.empty()||pos>=a.back()) 15 a.push_back(pos); 16 else 17 *upper_bound(a.begin(),a.end(),pos)=pos; 18 //for(int j=0;j<(int)a.size();++j) 19 // cout<<a[j]<<' '; 20 //cout<<endl; 21 } 22 printf("%d ",(int)a.size()); 23 return 0; 24 }