大体题意:
你在一个二维坐标轴上运动,每一行都有钻石,你竖直运动速度固定,是V,水平速度 是-V/R ~ V/R不等!你可以随时调整速度!刚开始你在Y轴0~w任意一个位置,求出你所吃的钻石的最大数目?
思路:
题解很巧妙,既然你可以随时调整速度,你为了吃到更多,只看最大速度就行了!
我们可以在每一个钻石求出一个覆盖范围,什么意思呢,既然水平速度 向左的最大值等于向右的最大值,那么肯定是一个等腰三角形了,只需要求出所有钻石在X轴上所有覆盖范围,求出 有多少个完全覆盖的钻石就是答案!
因此 我们可以给范围左端点进行从大到小排序,相同按照右端点从小到大排序,对右端点求最长上升子序列即可!
有个优化,如果一个钻石坐标是(X,Y)的话,那么覆盖左端点是X - Y/r,,右端点是X + Y/r,有小数存在误差,因此我们可以直接两边乘以r,因为我们只在意相对谁大谁小,并不在意大多少。所有可以乘以r避免小数,但是这样做会爆int,开long long 就好了!!
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
using namespace std;
const int maxn = 100000 + 7;
typedef long long ll;
struct Node{
ll s,e;
bool operator < (const Node & rhs) const {
return s > rhs.s || (s == rhs.s && e < rhs.e);
}
}p[maxn];
ll lcs[maxn];
int main(){
int n,r,w,h;
while(scanf("%d %d %d %d",&n,&r,&w,&h) == 4){
for (int i = 0; i < n; ++i){
int x,y;
scanf("%d %d",&x,&y);
p[i].s = (ll)r*(ll)x-(ll)y;
p[i].e = (ll)r*(ll)x+(ll)y;
}
sort(p,p+n);
lcs[0] = p[0].e;
int cnt = 1;
for (int i = 1; i < n; ++i){
if (p[i].e >= lcs[cnt-1]){
lcs[cnt++] = p[i].e;
}else {
int l = 0,r = cnt-1;
while(l <= r){
int mid = l+r>>1;
if (lcs[mid] >= p[i].e)r = mid - 1;
else l = mid + 1;
}
lcs[l] = p[i].e;
}
}
printf("%d\n",cnt);
}
return 0;
}