Description
Solution
很明显,如果两个向量是反向的,那么无论怎样一定可以找到
λ1,λ2
满足相加为0,剩下的部分要怎样解决呢?这里就要用到类欧几里得算法,就是一种迭代过程很像欧几里得算法的东东。
首先有第一个结论:若向量
a、b
的夹角
>π2
时,答案就是
min(|a|,|b|)
。
Proof.
设
p=|a|,q=|b|,p<q
,同时
cosα<12
则有
|aλ1+bλ2|=(pλ1)2+(qλ2)2+2pλ1qλ2cosα−−−−−−−−−−−−−−−−−−−−−−−−√
≥(pλ1)2+(qλ2)2−2pλ1qλ2cosα−−−−−−−−−−−−−−−−−−−−−−−−√
≥(|pλ1|−|qλ2|)2+pλ1qλ2−−−−−−−−−−−−−−−−−−−√
若是
x=0,y≠0
,就有
(|pλ1|−|qλ2|)2=|qλ2|2≥q2≥p2
若是
y=0,x≠0
,就有
(|pλ1|−|qλ2|)2=|qλ1|2≥p2
否则
|pλ1||pλ2|≥|p||q|≥p2
还有第二个结论:向量
(a,b)能够代替(a,b+ka)
,其中
k
为整数。有了这一条,我们就可以让两个向量夹角不断变大,进而达到夹角
Proof
设
|aλ1+bλ2|
为答案.转换后则有
|aλ1+bλ2|=|aλ1+bλ2+akλ2−akλ2|=|a(λ1−ky)+(b+ka)λ2|
此时我们考虑
k
的取值,要分类讨论。
当
当
|OA|<|OE|
时,就从
∠BCD、∠BDC
之中选一个较大角来转化。
第三个结论:
max(∠BCD,∠BDC)>∠AOB
Proof
∠BCD=∠AOB+∠OBC
有了这些结论,我们就可以解决这道题目了,不过要细心处理分类的条件(我被一个long long的平方坑了很长时间)。此外还有一些计算时候的小技巧。
- 向量的数量积: |a||b|cosθ=x1∗x2+y1∗y2
- 判断
max(∠BCD,∠BDC)
:判断
E
的落点与
CD 中点的关系。 -
k
的计算:
数量积|a|2 (证明详见这个博客)
Code
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
#define fo(i,a,b) for(i=a;i<=b;i++)
typedef long long ll;
ll x,y,xx,yy,ans1,ans2,ans;
ll dot,l1,l2,k;
bool bz;
ll sqr(ll x){return x*x;}
void deal(ll x,ll y,ll xx,ll yy,ll &ans1,ll &ans2){
ll dot=x*xx+y*yy,l1=sqr(x)+sqr(y),l2=sqr(xx)+sqr(yy);
//if(l1==0){bz=1;return;}
if(dot<0){
deal(x,y,-xx,-yy,ans1,ans2);ans2=-ans2;
return;
}
if(l1>l2){
deal(xx,yy,x,y,ans2,ans1);
return;
}
if(sqr(dot)*4<(l1*l2)|!l1){
ans1=1,ans2=0;
return;
}
ll k=dot/l1;
if(2*dot>l1*(2*k+1)){
deal(x,y,xx-(k+1)*x,yy-(k+1)*y,ans1,ans2);
ans1-=(k+1)*ans2;
}
else{
deal(x,y,xx-k*x,yy-k*y,ans1,ans2);
ans1-=k*ans2;
}
}
int main(){
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
while(scanf("%lld%lld%lld%lld",&x,&y,&xx,&yy)!=EOF){
ans=ans1=ans2=bz=0;
deal(x,y,xx,yy,ans1,ans2);
x*=ans1,y*=ans1,xx*=ans2,yy*=ans2;
ans=sqr(x+xx)+sqr(y+yy);
printf("%lld\n",ans);
}
}