正题
题目大意
有nnn个点,将两个点连成线,求斜率最接近PQ\frac{P}{Q}QP的线。
解题思路
我们有一个结论:若我们对于每一个点做一条斜率为PQ\frac{P}{Q}QP的线,然后按截距排序,然后答案必定是相邻的点。
证明:
我们在三条线上分别做点A,B,CA,B,CA,B,C,我们用tan(A,B)tan(A,B)tan(A,B)表示直线A,BA,BA,B的斜率
我们现在要证明tan(A,C)tan(A,C)tan(A,C)或tan(C,B)tan(C,B)tan(C,B)必定比tan(A,B)tan(A,B)tan(A,B)更接近PQ\frac{P}{Q}QP。
我们做AD⊥l1AD\perp l1AD⊥l1,做BE⊥l2BE\perp l2BE⊥l2,然后我们分类讨论。
- CCC点在ADADAD线的左边,此时我们发现CCC和BBB的距离显然比AAA和BBB的要远,所以斜率更接近。
- CCC点在BEBEBE线的右边,与上面同理
- CCC点在ADADAD的右边BEBEBE的左边此时我们有tan(AC)>PQ,tan(CB)>PQ,tan(AB)>PQtan(AC)>\frac{P}{Q},tan(CB)>\frac{P}{Q},tan(AB)>\frac{P}{Q}tan(AC)>QP,tan(CB)>QP,tan(AB)>QP,然后因为这个三角形中必定有一条边的斜率大于ABABAB,一条小于ABABAB,所以我们取叫小的那条就是更接近的。
那我们现在证明了三条时的情况,扩展到多条时是同理的。
证明完毕
所以我们可以对于每条线按照截距排序,然后只计算相邻的边即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const ll N=2e5+10;
struct node{ll a,b;
}ans,get;
struct point{ll x,y;double z;
}a[N];
ll n,x[N],y[N];
double operator-(const node &x,const node &y)
{return fabs(1.0*x.a/x.b-1.0*y.a/y.b);}
bool operator<(const node &x,const node &y)
{return 1.0*x.a/x.b<1.0*y.a/y.b;}
bool cMp(point x,point y)
{return x.z<y.z;}
int main()
{//freopen("slope.in","r",stdin);//freopen("slope.out","w",stdout);scanf("%lld%lld%lld",&n,&get.a,&get.b);for(ll i=1;i<=n;i++){scanf("%lld%lld",&a[i].x,&a[i].y);a[i].z=a[i].y*1.0-(double)(a[i].x*1.0*get.a*1.0/get.b);}sort(a+1,a+1+n,cMp);ans=(node){abs(a[2].y-a[1].y),abs(a[1].x-a[2].x)};for(ll i=3;i<=n;i++){node now=(node){abs(a[i].y-a[i-1].y),abs(a[i].x-a[i-1].x)};if((now-get)==(ans-get)&&now<ans) ans=now;else if(now-get<ans-get) ans=now;}ll q=ans.a,p=ans.b,d=__gcd(q,p);printf("%lld/%lld",q/d,p/d);
}