Description
Solution
设λ1=p,λ2=q
|pa+qb|2=p2|b|2+q2|a|2+2pa⋅qb
其中a⋅b是点积
所以
=p2|a|2+q2|b|2+2pq|a||b|cosθ
其中θ为两向量夹角。
我们知道θ是小于
π2也就是
90∘,或者说,对
90∘取模后绝对值小于
90∘。
有两个结论。
结论1
当θ≥60∘,最优答案就是min(|a|,|b|)2,也就是说,p,q一个是1,一个是0。
证明如下
当θ≥60∘,cosθ≤0.5
那么
|pa+pb|2≥p2|a|2+q2|b|2+pq|a||b|
=(pa)2+(qb)2+p|a|q|b|=(|pa|−|qb|)2+|pa||qb|
显然|pa||qb|≥min(|pa|,|qb|)2,(|pa|−|qb|)2≥0
所以最优解一定是min(|pa|,|qb|)2
结论2
(a,b)的答案等于(a,b+ka)的答案
这个完全可以自己画一个图,显然构成了平行四边形,对边是相等的。
此处不再赘述。
那么只需要不断变换,增大θ
显然从某一个向量向另一个向量所在直线作垂线,变换要尽量接近垂线(这样增大角度才多)。
点积除一下,然后再判断选垂线前面还是后面好,是0就强行+1.
然而我并不会证复杂度。
Code
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define INF 1000000000000
#define LL long long
#define N 100005
using namespace std;
LL x,y,x2,y2,t,ask[N][4];
LL ti(LL x,LL y,LL x2,LL y2)
{
return x*x2+y*y2;
}
LL len(LL x,LL y)
{
return x*x+y*y;
}
LL get(LL x,LL y,LL x2,LL y2)
{
LL l1=len(x,y),l2=len(x2,y2),t=ti(x,y,x2,y2);
if(x*y2==x2*y) return 0;
if(abs(t*1.0/sqrt(l1)/sqrt(l2))<0.5) return min(l1,l2);
LL v1=t/l1,v2=t/l2;
if(v2==0&&v1==0)
{
if(l1<l2) v1++;
else v2++;
}
if(v2!=0&&v1==0) return get(x-v2*x2,y-v2*y2,x2,y2);
else return get(x,y,x2-v1*x,y2-v1*y);
}
int main()
{
while(scanf("%lld%lld%lld%lld",&x,&y,&x2,&y2)!=EOF)
{
printf("%lld\n",get(x,y,x2,y2));
}
}