题目大意
给定两个向量,求 ∣ x a ⃗ + y b ⃗ ∣ |x\vec a+y\vec b| ∣xa+yb∣ 最小, x , y x,y x,y 不同时为0。
思路
约定: ∣ a ⃗ ∣ < ∣ b ⃗ ∣ |\vec a| < |\vec b| ∣a∣<∣b∣ ,且两个向量夹角小于 π 2 \frac{\pi}{2} 2π
Theorem1 :两个向量的夹角如果大于等于 π 3 \frac{\pi}{3} 3π ,则答案等于 m i n ( ∣ a ⃗ ∣ , ∣ b ⃗ ∣ ) min(|\vec a|,|\vec b|) min(∣a∣,∣b∣) 。
Proof:容易得到
∣ x a ⃗ + y b ⃗ ∣ 2 = ∣ a ⃗ ∣ 2 x 2 + ∣ b ⃗ ∣ y 2 + 2 x y ∣ a ⃗ ∣ ∣ b ⃗ ∣ c o s θ |x\vec a+y\vec b|^2=|\vec a|^2x^2+|\vec b|y^2+2xy|\vec a||\vec b|cos\theta ∣xa+yb∣2=∣a∣2x2+∣b∣y2+2xy∣a∣∣b∣cosθ
因为 π 3 ≤ θ ≤ π 2 \frac{\pi}{3}\le\theta\le\frac{\pi}{2} 3π≤θ≤2π ,所以
≥ ∣ a ⃗ ∣ 2 x 2 + ∣ b ⃗ ∣ y 2 + x y ∣ a ⃗ ∣ ∣ b ⃗ ∣ ≥ ∣ ( ∣ a ⃗ ∣ x − ∣ b ⃗ ∣ y ) 2 + x y ∣ a ⃗ ∣ ∣ b ⃗ ∣ \ge|\vec a|^2x^2+|\vec b|y^2+xy|\vec a||\vec b| \\ \ge|(|\vec a|x - |\vec b|y)^2+xy|\vec a||\vec b| ≥∣a∣2x2+∣b∣y2+xy∣a∣∣b∣≥∣(∣a∣x−∣b∣y)2+xy∣a∣∣b∣
当 x = 0 , y ≠ 0 x = 0, y\not=0 x=0,y=0 时, ∣ b ⃗ ∣ 2 y 2 ≥ ∣ b ⃗ ∣ 2 ≥ ∣ a ⃗ ∣ 2 |\vec b|^2y^2\ge|\vec b|^2\ge|\vec a|^2 ∣b∣2y2≥∣b∣2≥∣a∣2
当 x ≠ 0 , y = 0 x\not=0,y=0 x=0,y=0 时, ∣ a ⃗ ∣ 2 x 2 ≥ ∣ a ⃗ ∣ 2 |\vec a|^2x^2\ge|\vec a|^2 ∣a∣2x2≥∣a∣2
否则 x y ∣ a ⃗ ∣ ∣ b ⃗ ∣ ≥ ∣ a ⃗ ∣ ∣ b ⃗ ∣ ≥ ∣ a ⃗ ∣ 2 xy|\vec a||\vec b|\ge|\vec a||\vec b|\ge|\vec a|^2 xy∣a∣∣b∣≥∣a∣∣b∣≥∣a∣2 。
所以答案为二者最小值。
Theorem2: ∣ x a ⃗ + y b ⃗ ∣ = ∣ ( x − k y ) a ⃗ + y ( b ⃗ + k a ⃗ ) ∣ |x\vec a+y\vec b|=|(x-ky)\vec a+y(\vec b+k\vec a)| ∣xa+yb∣=∣(x−ky)a+y(b+ka)∣
以上证明显然。
发现可以用类似扩欧的做法来做。但如何选择 k k k 为一大难题。
如图,过点 B B B 做 B E ⊥ O A BE⊥OA BE⊥OA 于 E E E。
我们定义 O A → = a ⃗ , O B → = b ⃗ , O C → = c ⃗ , O D → = d ⃗ \overrightarrow{OA}=\vec a,\overrightarrow{OB}=\vec b,\overrightarrow{OC}=\vec c,\overrightarrow{OD}=\vec d OA=a,OB=b,OC=c,OD=d,且 c ⃗ = k a ⃗ , d ⃗ = ( k + 1 ) a ⃗ \vec c=k\vec a,\vec d=(k+1)\vec a c=ka,d=(k+1)a ,且点 C , D C,D C,D 在 E E E 点两边。则 k k k 可以推式子(求 O E OE OE 长再除以 ∣ a ⃗ ∣ |\vec a| ∣a∣)或二分求得。
容易发现 B C → , a ⃗ \overrightarrow{BC},\vec a BC,a 或 B D → , a ⃗ \overrightarrow{BD},\vec a BD,a 的答案等于 a ⃗ , b ⃗ \vec a,\vec b a,b 的答案。其次我们发现 m a x ( ∠ B C D , ∠ B D C ) > ∠ A O B max(\angle BCD,\angle BDC)>\angle AOB max(∠BCD,∠BDC)>∠AOB 。所以若 ∠ B C D > ∠ B D C \angle BCD>\angle BDC ∠BCD>∠BDC 则选择 B C → \overrightarrow{BC} BC,否则选择 B D → \overrightarrow{BD} BD 。判断角的大小可以采用大边对大角的方法。
然后就可以递归求解。边界情况即是夹角大于 π 3 \frac{\pi}{3} 3π 。
注意:
- 两个向量共线的情况答案为0
- 若两个向量的夹角大于 π 2 \frac{\pi}{2} 2π ,则可以对任意一个向量关于原点作中心对称。
Code
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
#define sqr(x) (x * x)
#define pi M_PI
#define ll long long
using namespace std;
ll ans;
struct node {ll x, y;ll len() {return x * x + y * y;}node operator + (const node & s) const {return (node){x + s.x, y + s.y};}node operator - (const node & s) const {return (node){x - s.x, y - s.y};}node operator * (const ll & s) const {return (node){x * s, y * s};}ll operator * (const node & s) const {return x * s.x + y * s.y;}
}a, b;
ll work(node a, node b) {if (a.x * b.y - a.y * b.x == 0) return 0;if (a.len() > b.len()) swap(a, b);if (a * b < 0) a.x = -a.x, a.y = -a.y;if (sqr((a * b * 2)) < a.len() * b.len()) return min(a.len(), b.len());ll k = (a * b) / a.len();node c = a * k, d = a * (k + 1);if ((b - c).len() < (b - d).len() && k) return work(b - c, a);else return work(b - d, a);
}
int main() {freopen("math.in", "r", stdin);freopen("math.out", "w", stdout);while (~scanf("%lld%lld%lld%lld", &a.x, &a.y, &b.x, &b.y))printf("%lld\n", work(a, b));fclose(stdin);fclose(stdout);return 0;
}