二维欧几里得——【NOI2014模拟7.11】数学题

这里写图片描述

神题……

由于我水平不够, 只得模模糊糊讲一下。

要求的东西,就相当于以两个向量作三角形的第三条边长的平方。


结论1:

我们知道有余弦定理, 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)


结论2:

(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)。同理可证相反方向。


二维欧几里得——【NOI2014模拟7.11】数学题_第1张图片

再看一下上面这幅图,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)));
    }
}

你可能感兴趣的:(二维欧几里得——【NOI2014模拟7.11】数学题)