神题……
由于我水平不够, 只得模模糊糊讲一下。
要求的东西,就相当于以两个向量作三角形的第三条边长的平方。
我们知道有余弦定理, c ^ 2 = a ^ 2 + b ^ 2 - 2 * a * b * cos(C)
设lamb1 = l1, lamb2 = l2
当cos(C) >= 1/2
c^2 >= a^2 * l1 ^ 2+b^2 * l2 ^ 2-a * b * l1 * l2
>= (a ^ 2 * l1 ^ 2 - b ^ 2 * l2 ^ 2) + a * b * l1 * l2
易得 c^2 >= min(a, b)
(a, b)所对应的答案,和(a, b + ka)一致,其中k为整数。
令|ax+by|为所求答案,则|a(x−ky)+(b+ka)y|也是,即(x, y)对应着答案(x−ky, y)。
并且若(x, y) ̸= (0, 0),则(x − ky, y) ̸= (0, 0)。同理可证相反方向。
再看一下上面这幅图,BC垂直于OA的延长线OD上。
∠BCD = ∠CBO + BOC, ∴∠BCD >∠BOC
–> –> –>
cb=ob-oc
根据结论2, Ans(CB,OA) = Ans(OA,OB)
我们可以这样迭代,知道COS(C)大于1/2,就可以直接求答案,复杂度不会证明,据说是log的。
COS(C)的求法就是两个向量的点积除以模长的乘积。
至于垂线那儿,可以打计算几何或直接上一次函数。
Code:
#include
#include
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? -(a) : (a))
using namespace std;
struct node {
double x, y;
}a, b;
double len(node a) {return sqrt(a.x * a.x + a.y * a.y);}
double movie(node a,node b) {return abs(a.x * b.x + a.y * b.y);}
node cro(node a,node b) {
node c;
if(a.x == 0) {
c.x = 0; c.y = b.y; return c;
}
if(a.y == 0) {
c.x = b.x; c.y = 0; return c;
}
double k = -a.x/a.y, bb = b.y - b.x * k;
double x = bb / (a.y / a.x - k), y = x * (a.y / a.x);
c.x = x; c.y = y; return c;
}
int main() {
freopen("math.in", "r", stdin);
freopen("math.out", "w", stdout);
while(scanf("%lf %lf %lf %lf", &a.x, &a.y, &b.x, &b.y) != EOF) {
while(movie(a, b) / len(a) / len(b) > 0.5) {
if(len(a) > len(b)) {
node c = a; a = b; b = c;
}
node c = cro(a, b);
int k = len(c) / len(a);
if(k == 0) k = 1;
node newa; newa.x = b.x - a.x * k; newa.y = b.y - a.y * k;
b = a; a = newa;
}
printf("%.0lf\n", min(movie(a, a), movie(b, b)));
}
}