• jzoj3736. 【NOI2014模拟7.11】数学题


    Description

    在这里插入图片描述

    Input

    输入有多组测例,每组测例有一行,为4 个整数x1,y1, x2, y2,含义见题目描述。输入文件以EOF 结束。

    Output

    在这里插入图片描述

    Sample Input

    3 0 1 2
    6 0 4 0

    Sample Output

    5
    0

    Data Constraint

    在这里插入图片描述

    赛时

    比赛一眼没啥思路,主要是感觉感冒了,精神状态欠佳。
    画画图,瞎**猜了一个神奇的结论:
    当两条向量的斜率相同时,答案为0。
    当两条向量不相同时,答案就是选择其中一条最短的。
    感觉没啥问题,接着去死磕后面的两道毒瘤题了。
    比赛即将结束,突然发现结论好像有点问题?
    /<_

    题解

    我们看看上面我的结论哪里错了——
    看到两个夹角等于120°,长度相等的向量。
    那么两个向量加起来是等于向量长的。
    如果把这个夹角变大点,那么长度就小于向量长了。
    所以说,我们要把这类型的情况给做好!

    直接上1号结论——当两向量夹角的角度大于60°时,即可利用我的结论。
    否则就看到2号结论,再搞搞事情。

    证明1号结论:
    在这里插入图片描述
    我直接截取论文上的证明了,还是很好推的(话说论文一开始写错了,那个等于号应该是大于等于)

    然后我们来看看2号结论:
    (|ax+by|=|a(x-lambda y)+(b+alambda)y|),即向量((x,y))可以转换成((x-lambda y,y)),且系数((a,b))可以转换成系数((a,b+alambda))
    证明显然。
    由于系数这个东西是自己随意确定的。
    所以,向量就可以利用上面的东西变成新的向量,同时扩大夹角。
    因此在不停地扩大的过程中,夹角也最终会大于60°,回到结论1即可。

    那么我们来看看具体如何扩大:
    还是论文的图
    在这里插入图片描述
    我们设(overrightarrow {OE})(overrightarrow {OB})(overrightarrow {OA})上的投影。
    那么接下来有3种情况:

    1、(|overrightarrow {OA}|<|overrightarrow {OE}|)
    在这种情况下,也就是上面的图,考虑转化。
    (overrightarrow {OC}=lambda*overrightarrow {OA})并且其中的(lambda)在满足(|overrightarrow {OC}|<|overrightarrow {OE}|)的情况下(lambda)最大。
    那么现在就可以转化啦。
    显然,(angle{DCB}>angle{AOB})
    于是我们就把((overrightarrow {CB},overrightarrow {OA}))代入,继续递归。

    2、(|overrightarrow {OA}|>|overrightarrow {OE}|)
    也就是类似于上面的(overrightarrow {OD})
    我们发现,(angle{ADB}>angle{AOB}),证明的话把D按照E轴对称折叠过去,发现是外角。
    ((overrightarrow {DB},overrightarrow {OA}))代入,递归!

    3、(|overrightarrow {OA}|=|overrightarrow {OE}|)
    其实这种情况注意一下即可,写得不正确有可能会死循环。

    大致就是这样子,是不是很像gcd算法的过程?这就叫做类欧几里得算法。
    一些小细节:

    • 如何快速求(lambda)呢?
      (lambda=lfloor frac{|overrightarrow {OE}|}{|overrightarrow {OA}|} floor)
    • 当递归后夹角大于90°,一样要把一条向量旋转180°。
    • 时间复杂度:因为有了上面这条,所以时间复杂度证明变得极其复杂。(其实是我太蔡了)

    标程

    uses math;
    type
            nod=record
                    x,y:extended;
            end;
    
    var
            i,j,k,l,n,m,anss:longint;
            co,kk:extended;
            a,b,c:nod;
    
    function jia(a,b:nod):nod;
    begin
            jia.x:=a.x+b.x;
            jia.y:=a.y+b.y;
    end;
    
    function jian(a,b:nod):nod;
    begin
            jian.x:=a.x-b.x;
            jian.y:=a.y-b.y;
    end;
    
    function cheng(lid:extended;a:nod):nod;
    begin
            cheng.x:=lid*a.x;
            cheng.y:=lid*a.y;
    end;
    
    function cross(a,b:nod):extended;
    begin
            exit(a.x*b.x+a.y*b.y);
    end;
    
    function dis(a:nod):extended;
    begin
            exit(sqrt(a.x*a.x+a.y*a.y));
    end;
    
    function ans(a:nod):extended;
    begin
            exit(a.x*a.x+a.y*a.y);
    end;
    
    function likegcd(a,b:nod):extended;
    var
            c:nod;
            det,k:extended;
    begin
            if (dis(a)>dis(b)) then
            begin
                    c:=a;a:=b;b:=c;
            end;
            if (dis(a)=0) then
            begin
                    exit(0);
            end;
            if (dis(b)=0) then
            begin
                    exit(0);
            end;
            co:=cross(a,b)/(dis(a)*dis(b));
            if (co<0) then
            begin
                    a.x:=-a.x;
                    a.y:=-a.y;
                    exit(likegcd(a,b));
            end;
            if (co=1) then
            begin
                    exit(0);
            end;
            c.x:=b.x*co;
            c.y:=b.y*co;
            kk:=pi;
            if (co<=1/2) then
            begin
                    if (dis(a)>dis(b)) then exit(ans(b))
                    else exit(ans(a));
            end;
            if (dis(a)>dis(c)) then
            begin
                    exit(likegcd(jian(b,a),a));
            end
            else
            begin
                    k:=trunc(dis(c)/dis(a));
                    exit(likegcd(jian(b,cheng(k,a)),a));
            end;
    end;
    
    begin
            assign(input,'math.in');reset(input);
            assign(output,'math.out');rewrite(output);
            while not eof do
            begin
                    readln(a.x,a.y,b.x,b.y);
                    c.x:=-a.x;
                    c.y:=-a.y;
                    if dis(jia(c,b))>dis(jia(a,b)) then a:=c;
                    anss:=trunc(likegcd(a,b));
                    writeln(anss);
                    if anss=5584 then
                    i:=i;
            end;
    end.
    
    
  • 相关阅读:
    学习软件工程的个人总结
    结对编程——黄金点游戏
    读取程序字符,行数,单词的个人程序
    c#代码分析
    Visual Studio2013的安装过程及练习测试
    小学三年级出题程序
    超级课程表的个人评价
    对软件工程的个人困惑
    个人附加作业
    个人最终总结
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11333812.html
Copyright © 2020-2023  润新知