其他分享
首页 > 其他分享> > 3736. 【NOI2014模拟7.11】数学题(math)

3736. 【NOI2014模拟7.11】数学题(math)

作者:互联网

Description

给定两个向量 \(\mathbf{a}=\left(x_{1}, y_{1}\right), \mathbf{b}=\left(x_{2}, y_{2}\right)\) 。求出一对整数 \(\lambda_{1}, \lambda_{2}\), 使得 \(\left|\lambda_{1} \mathbf{a}+\lambda_{2} \mathbf{b}\right|\) 最小 \((|\mathrm{v}|\) 表示向量 \(\mathrm{v}\) 的长度 \()\) 。要求 \(\lambda_{1}, \lambda_{2}\) 不同时为 0 。

Solution

引理 1:当两向量夹角 \(\theta>\frac{\pi}{3}\),即 \(\cos \theta<\frac{1}{2}\) 时,答案为\(\min(|\vec{a}|,|\vec{b}|)^2\)。

证明:

令 \(p=|a|,q=|b|\),不妨设 \(p<q\),则

\(\begin{aligned}|\vec{a}x+\vec{b}y|&=\sqrt{(px)^2+(qy)^2-2pxqy\cos \theta}\\&\ge\sqrt{|px|^2+|qy|^2-2|px||qy|\cos \theta}\\&\ge\sqrt{|px|^2+|qy|^2-|px||qy|}\\&\ge\sqrt{(|px|-|qy|)^2+|px||qy|}\end{aligned}\)

若 \(x=0\),则 \(y\not=0\),\((|px|-|qy|)^2=|qy|^2\ge q^2\ge p^2\)

若 \(y=0\),则 \(x\not=0\),\((|px|-|qy|)^2=|px|^2\ge p^2\)

否则 \(|px||qy|\ge |p||q|\ge p^2\)

引理 2:\((a,b)\) 所对应的答案,和 \((a,b+ka)\) 一致,其中 \(k\) 为整数。

证明:

令 \(|ax+by|\) 为所求答案,则 \(|a(x-ky)+(b+ka)y|\) 也是,即 \((x,y)\) 对应着答案 \((x-ky,y)\)。并且若 \((x,y)\not=(0,0)\),则 \((x-ka,y)\not=(0,0)\)。同理可证相反方向。

根据这两个引理,那么使用欧几里得算法就是显而易见的。

通过引理 2 的变换,将两向量的夹角满足引理 1 的条件,就是我们的目标。

但我们还要求出在引理 2 中提到的 \(k\)。这里我们规定 \(|\vec{a}|\le|\vec{b}|\)。

令 \(c=ka\)。

如果 \(k<1\),那么可以证得 \(\vec{b}=\vec{b}-\vec{a}\) 是符合要求的变换。

如果 \(k>1\),那么将 \(k\) 下取整,即可保证 \(ka\le c\),那么 \(\vec{b}=\vec{b}-\vec{a}k\)即可。

Code

#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long
#define db double
using namespace std;
struct node
{
    ll x,y;
    db len() {return sqrt((db)x*x+y*y);}
    int operator*(node b) {return x*b.x+y*b.y;}
    node operator*(ll b) {return (node){x*b,y*b};}
    node operator+(node b) {return (node){x+b.x,y+b.y};}
    node operator-(node b) {return (node){x-b.x,y-b.y};}
}x,y,z;
db calc_cos(node a,node b) {return (db)(a*b)/(a.len()*b.len());}
int main()
{
    freopen("math.in","r",stdin);
    freopen("math.out","w",stdout);
    while (scanf("%lld%lld%lld%lld",&x.x,&x.y,&y.x,&y.y)!=EOF)
    {
        if (x.x*y.y==x.y*y.x)
        {
            printf("%d\n",0);
            continue;
        }
        if (x*x>y*y) swap(x,y);
        if (x*y<0) y=y*-1;
        db co=calc_cos(x,y);
        while (co>0.5)
        {
            if (x*x>y*y) swap(x,y);
            if (x*y<0) y=y*-1;
            if (x*y/(x*x)<=1) y=y-x;
            else
            {
                z=x*(x*y/(x*x));
                y=y-z;
            }
            co=calc_cos(x,y);
        }
        printf("%lld\n",min(x*x,y*y));
    }
    return 0;
}

标签:node,return,7.11,qy,px,NOI2014,ge,vec,3736
来源: https://www.cnblogs.com/Livingston/p/15799838.html