【NOI2014】数学题(math)

本文介绍了一种类似欧几里得算法的迭代方法,用于解决特定向量问题。主要内容包括三个关键结论及其证明过程,通过调整向量夹角以简化问题并找到最小化向量组合长度的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

这里写图片描述

Solution

很明显,如果两个向量是反向的,那么无论怎样一定可以找到 λ1,λ2 满足相加为0,剩下的部分要怎样解决呢?这里就要用到类欧几里得算法,就是一种迭代过程很像欧几里得算法的东东。
首先有第一个结论:若向量 ab 的夹角 π2 时,答案就是 min(|a|,|b|)
Proof.
p=|a|,q=|b|,pq ,同时 cosα12
则有 |aλ1+bλ2|=(pλ1)2+(qλ2)2+2pλ1qλ2cosα
(pλ1)2+(qλ2)22pλ1qλ2cosα
(|pλ1||qλ2|)2+pλ1qλ2
若是 x=0y0 ,就有 (|pλ1||qλ2|)2=|qλ2|2q2p2
若是 y=0x0 ,就有 (|pλ1||qλ2|)2=|qλ1|2p2
否则 |pλ1||pλ2||p||q|p2
还有第二个结论:向量 (a,b)(a,b+ka) ,其中 k 为整数。有了这一条,我们就可以让两个向量夹角不断变大,进而达到夹角π2,然后直接求出答案。
Proof
|aλ1+bλ2| 为答案.转换后则有
|aλ1+bλ2|=|aλ1+bλ2+akλ2akλ2|=|a(λ1ky)+(b+ka)λ2|
此时我们考虑 k 的取值,要分类讨论。
这里写图片描述
|OA||OE|时,就有 OABAOB ,我们就可以转化成一个比较大的角度了。
|OA||OE| 时,就从 BCDBDC 之中选一个较大角来转化。
第三个结论 max(BCDBDC)AOB
Proof
∠BCD=∠AOB+∠OBC
有了这些结论,我们就可以解决这道题目了,不过要细心处理分类的条件(我被一个long long的平方坑了很长时间)。此外还有一些计算时候的小技巧。

  1. 向量的数量积: |a||b|cosθ=x1x2+y1y2
  2. 判断 max(BCDBDC) :判断 E 的落点与CD中点的关系。
  3. 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值