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