0
点赞
收藏
分享

微信扫一扫

[JZOJ3736] 数学题


Description

[JZOJ3736] 数学题_#include


[JZOJ3736] 数学题_欧几里得_02


[JZOJ3736] 数学题_#define_03

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));
}
}


举报

相关推荐

0 条评论