【jzoj3736】【数学题】【类欧几里德】

来源:互联网 发布:青岛知豆电动车出租 编辑:程序博客网 时间:2024/06/06 23:44

题目大意

这里写图片描述

解题思路

观察可知当向量夹角cos大于1/2时模长最小的向量即答案。

向量a,b模长为p,q,夹角余弦cos。

|ax+by|=((px)2+(qy)2+2pxqycos)

>=((px)2+(qy)22|px||qy|cos)

>=((px)2+(qy)2|px||qy|)

>=((pxqy)2+|px||qy|)

发现无论怎么样都不会比模长最小的向量小。

我们考虑把两个向量答案转化成两个夹角更大的向量的答案。(a+b)=(a+b+ka)。(ax+by)=(a(x+k)+by)。

这里写图片描述

考虑把模长大的向量放在下面,向量OC,OD是b+ak最接近E的两个向量OC+OB=CB,DC=-OA,DB=-(OD-OB),发现同时取反答案不变,所以可以把向量夹角变大,选一个夹角更大的变即可。实践可以证明变换次数不会超过log级别。

code

#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define LF double#define LL long long#define Min(a,b) ((a<b)?a:b)#define Max(a,b) ((a>b)?a:b)#define Fo(i,j,k) for(LL i=j;i<=k;i++)#define Fd(i,j,k) for(LL i=j;i>=k;i--)using namespace std;LL const Mxa=1e4,Inf=1e9;LF Eps=1e-6;LL X1,X2,Y1,Y2;LL Dot(LL X1,LL Y1,LL X2,LL Y2){    return X1*X2+Y1*Y2;}LF Abs(LL X1,LL Y1){    return sqrt(X1*X1+Y1*Y1);}int main(){    //freopen("math.in","r",stdin);    //freopen("math.out","w ",stdout);    freopen("d.in","r",stdin);    freopen("d.out","w ",stdout);    LF Cos,M1,M2;    while(scanf("%lld%lld%lld%lld",&X1,&Y1,&X2,&Y2)!=EOF){        if(Dot(X1,Y1,X2,Y2)<0)            X1=-X1,Y1=-Y1;        LF xx=Dot(X1,Y1,X2,Y2),x=Abs(X1,Y1),y=Abs(X2,Y2);        if(X1*Y2==X2*Y1){printf("0\n");continue;}        while((Cos=Dot(X1,Y1,X2,Y2)/Abs(X1,Y1)/Abs(X2,Y2))>0.5){            M1=Abs(X1,Y1),M2=Abs(X2,Y2);            if(M1>M2+Eps)swap(X1,X2),swap(Y1,Y2),swap(M1,M2);            LL Tmp=M2/M1;            if(M2*Cos-M1*Tmp<M1*(Tmp+1)-M2*Cos)                X2-=X1,Y2-=Y1;            else X2=-X1*(Tmp+1)+X2,Y2=-Y1*(Tmp+1)+Y2,X1=-X1,Y1=-Y1;        }        printf("%lld\n",Min(X1*X1+Y1*Y1,X2*X2+Y2*Y2));    }    return 0;}
0 0
原创粉丝点击