Wannafly挑战赛15 E 小W的斜率

题目描述 

小W非常喜欢某个有理数P/Q,而且他非常喜欢用它来进行一些玄学操作。他在二维平面上撒下了n个点,这些点相互不同,但一番观察之后,他失望的发现并没有任何两个点连成的直线的斜率是P/Q。你能不能告诉他在这些斜率中最接近P/Q的是多少。

输入描述:

 
  

第一行包括三个正整数n,P,Q(5<=n<=106,1<=P,Q<=105)

接下来n行,每行两个正整数x,y表示点的坐标(0<=x,y<=109)

输出描述:

一个有理数P’/Q’表示最接近P/Q的斜率
示例1

输入

6 15698 17433
112412868 636515040
122123982 526131695
58758943 343718480
447544052 640491230
162809501 315494932
870543506 895723090

输出

193409386/235911335

备注:

保证答案唯一,且P’/Q’>0
斜率为无穷时可表示为1/0


官方题解:

虽然题目描述的是斜率最接近,但实际上和求角度最接近没有太大的差别。

只不过两边最接近比较不太一样。
所以可以不妨先旋转坐标系或者说把点按照 y-kx 排序,把问题转化为斜率绝对值最大的两个点,因为保证了不存在斜率等于所求值,所以不存在斜率是无穷
的情况。现在证明 X 相邻的两个点一定存在斜率最大。设点 A,B 是所求最接近斜
率,且 A,B 不相邻,其中间存在 C,AB 斜率可表示为(Ay-By)/(Ax-Bx)=((Ay-Cy)+(Cy-
By))/((Ax-Cx)+(Cx-Bx))所以在(Ay-Cy)/(Ax-Cx)和(Cy-By)/(Cx-Bx)两项中必然存在
一项大于等于 AB 斜率,即答案必存在于相邻的两点中。
枚举相邻两点的斜率,比较得到答案。


代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
int n;
ll P,Q;
struct Point
{
    ll x,y;
    bool operator < (const struct Point &a) {
        return (Q * y - P * x) < Q * a.y - P * a.x;
    }
}points[maxn];
int main()
{
    while(~scanf("%d%lld%lld",&n,&P,&Q))
    {
        for(int i=0;i<n;i++) scanf("%lld%lld",&points[i].x,&points[i].y);
        sort(points,points+n);
        ll up = 0,down = 1; 
        for(int i=1;i<n;i++) 
        {
            if(points[i].x == points[i-1].x) continue;
            double temp = double(points[i].y - points[i-1].y) / (points[i].x - points[i-1].x);
            double rate = double(up) / down;
            double ok = double(P) / Q;
            if(fabs(rate - ok) > fabs(temp - ok))  
            {
                up = points[i].y - points[i-1].y;
                down = points[i].x - points[i-1].x;
            }
        }
        ll gcd = __gcd(up,down);
        printf("%lld/%lld\n",up/gcd,down/gcd);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/m0_38013346/article/details/80340069