Description
Input
Output
Sample Input
6 15698 17433
112412868 636515040
122123982 526131695
58758943 343718480
447544052 640491230
162809501 315494932
870543506 895723090
Sample Output
193409386/235911335
Data Constraint
Solution
题意是给你n个点和P,Q,要你求两个点构成的斜率最接近于P/Q,以“A/B”的形式输出斜率。
相当于是然你求(y1-y2)/(x1-x2) 最接近于P/Q的值X和Y。
通分,得到:
Q(y1-y2)/Q (x1-x2)最接近于P(x1-x2)/Q(x1-x2)
将分母去掉:
Q(y1-y2)最接近于P(x1-x2)
拆项:
Qy1-Qy2最接近于Px1-Px2
移项:
Qy1-Px1最接近于Qy2-Px2
至此,我们只用对每一个点的上式排一遍序,去相邻的比较即可。
考虑另一种思路。
我们将式子拆成:
| Q(y1-y2) / Q(x1-x2)-P(x1-x2) / Q(x1-x2) |最小
| ((Q(y1-y2)-P(x1-x2)) / Q(x1-x2) |最小
| ((Qy1-Px1)-(Qy2-Px2)) / Qx1-Qx2 |最小
我们将这个式子看成斜率的形式,
即Q(y1-Px1)=Y1,Q(y2-Px2)=Y2,Qx1=X1,Qx2=X2,得:
| (Y1-Y2)/(X1-X2) | 最小
也就是我们将每个点用上式变成一个新点,再求两个点所构成的斜率的绝对值最小值。
若两个纵坐标直接有一个点,那么这中间点于两边点构成的斜率总有一个会比两边点构成的斜率小。
因此我们将点按照纵坐标排序,
用两两相邻的纵坐标更新答案即可。
注意精度问题。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define N 200010
#define db long double
using namespace std;
ll n,P,Q,Ax,Ay,d;
db ans=1e17;
struct node{ll x,y,z;}a[N];
ll gcd(ll x,ll y){
if(x%y==0) return y;
return gcd(y,x%y);
}
I cmp(node a,node b){return a.z>b.z;}
db S(db x){
if(x<0) return -x;
return x;
}
I main(){
freopen("slope.in","r",stdin);
freopen("slope.out","w",stdout);
scanf("%lld%lld%lld",&n,&P,&Q);
F(i,1,n){
scanf("%lld%lld",&a[i].x,&a[i].y);
a[i].z=Q*a[i].y-P*a[i].x;
}
sort(a+1,a+1+n,cmp);
F(i,1,n-1){
db s=S((db)(a[i].y-a[i+1].y)/(db)(a[i].x-a[i+1].x)-(db)P/(db)Q);
if(ans>s){
ans=s;
Ax=a[i].y-a[i+1].y;
Ay=a[i].x-a[i+1].x;
}
}
d=gcd(Ax,Ay);
printf("%lld/%lld\n",Ax/d,Ay/d);
return 0;
}
作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/99697172