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

题目大意

这里写图片描述

解题思路

观察可知当向量夹角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)。

【jzoj3736】【数学题】【类欧几里德】_第1张图片

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

code

#include
#include
#include
#include
#define LF double
#define LL long long
#define Min(a,b) ((a
#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*(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;
}

你可能感兴趣的:(【jzoj3736】【数学题】【类欧几里德】)