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

来源:互联网 发布:阿里云的钱怎么提现 编辑:程序博客网 时间:2024/06/08 12:07

这里写图片描述

神题……

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

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


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


这里写图片描述

再看一下上面这幅图,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<cmath>#include<cstdio>#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)));    }}
1 0
原创粉丝点击