#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);} #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;} template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;} const int N=1e5+10,M=0,Z=1e9+7,ms63=1061109567; pair<LL,LL>a[N]; int n,r,w,h; LL x,y; LL d[N]; int main() { while(~scanf("%d%d%d%d",&n,&r,&w,&h)) { for(int i=1;i<=n;++i) { scanf("%lld%lld",&x,&y); a[i].first=r*x+y;a[i].second=-r*x+y; } sort(a+1,a+n+1); d[0]=-1e18;int len=0; for(int i=1;i<=n;++i) { if(a[i].second>=d[len])d[++len]=a[i].second; else { int p=lower_bound(d+1,d+len+1,a[i].second)-d; d[p]=a[i].second; } } printf("%d\n",len); } return 0; } /* 【trick&&吐槽】 这道题真是学到了新知识啊啊啊! 【题意】 给你一个w*h的矩形,也可以代表二维平面,w和h都在[1,1e9]范围内。 我们一开始可以选择在y==0的任一位置。然后对于我们的速度,并不知道。 但是可以知道的是,如果纵向速度是v,那么横向速度就在[-v/r,v/r]之间。r的取值范围是[1,10]的整数 矩形中有n(1e5)个点,坐标两两不同。问你,我们最多能抵达多少个点。 【类型】 坐标变换 最长上升序列(LIS) 【分析】 这道题非常地巧妙啊!做法是这样引入的—— 首先,如果r==1,那么我们可以把这个矩形的坐标轴顺时针移动45度。 这时,我们如果把所有点按照这个坐标轴排序。那么一个LIS就是我们的答案了。 问题,如何把所有点,按照新的坐标轴排序呢? 首先,坐标是二维状态。而且我们还要求LIS。 于是,我们要先对一维做升序排序,这样只需要使得第二维也保证升序。 那么,对于r,排序的双关键字就是(rx+y,-xr+y)。 这个等价是如何实现的呢? (x,y),向左上走,走到的是(x-1,y+r) 这两个点在第一维度排序上要是等价的,设两个坐标的估价为(p,q),那么有-1p+rq==0, 于是第一维度的映射成了p==rq,即(r,1),即(rx+y) (x,y),向右上走,走到的是(x+1,y+r) 这两个点在第二维度排序上要是等价的,设两个坐标的估价为(p,q),那么有+1p+rq==0, 于是第一维度的映射成了p==-rq,即(-r,1),即(-rx+y) 这样就保证了,我们始终是在合法的角度范围行走,于是就可以转化为LIS,AC掉这题啦! 【时间复杂度&&优化】 O(nlogn) */