题目

传送门 to CF

题目概要
格点图中从 (0,0)(0,0)(0,0) 走到 (n,m)(n,m)(n,m),要求每一步都只能沿着一条线段从一个格点走到另一个,并且这个线段上除了端点是没有格点的。更重要的是,相邻两步的线段不能共线。求最短距离。

数据范围与提示
max⁡(n,m)≤1018\max(n,m)\le 10^{18}max(n,m)≤1018(因为我们有 O(log⁡n)\mathcal O(\log n)O(logn) 的做法)。

思路

为啥我这么笨啊……不像 sysysy 看一眼就会……

给出一个重要结论:最优路径最多需要一个中转点

证明就比较骚气。如果有两个中转点,比如 s→a→b→ts\rightarrow a\rightarrow b\rightarrow ts→a→b→t,那么我们直接改造为 s→b→ts\rightarrow b\rightarrow ts→b→t 。首先你得承认,路径长度变小了(因为 s→as\rightarrow as→a 和 a→ba\rightarrow ba→b 不共线,两边之和大于第三边)。但是目前可能不合法。

考虑用 调整法。对于任意 s→x→ts\rightarrow x\rightarrow ts→x→t,不妨设 s→xs\rightarrow xs→x 撞到了 yyy(如果是 x→tx\rightarrow tx→t 撞到了别人同理)。改成 s→y→ts\rightarrow y\rightarrow ts→y→t 就好。你得承认,路径长度又在变小(因为 y→xy\rightarrow xy→x 和 x→tx\rightarrow tx→t 不共线,两边之和大于第三边),绝妙的是,形成的三角形面积在变小。如果仍然不合法,就继续调整就行,一定会有出口——以 sss 和 ttt 为其中两个顶点的三角形的面积只有 nmnmnm 个,面积不会无限缩小!

既然已经证明了这个……好像还是不太会做的样子……

再给出一个结论:中转点距离 “直达航线” 距离最短。尽管这个想法很自然,结论似乎也很显然,我们还是要证明一下。这里的 “直达航线” 指的就是 y=mn⋅xy=\frac{m}{n}\cdot xy=nm​⋅x 这条直线。

显然,在任意一条平行于 “直达航线” 的直线上,相邻的整点距离相同(因为一定是横坐标差 ngcd⁡(n,m)n\over{\gcd(n,m)}gcd(n,m)n​,纵坐标相差 mgcd⁡(n,m)m\over \gcd(n,m)gcd(n,m)m​ 嘛)。不妨设这个距离是 LLL,那么 (0,0)(0,0)(0,0) 到 (n,m)(n,m)(n,m) 至少是 2L2L2L(否则二者可直达)。

如果一个中转点与 (0,0),(n,m)(0,0),(n,m)(0,0),(n,m) 形成的三角形中,有别的合法中转点(可以在边上,非顶点即可),那么该中转点不优。理由是,画图可知,如果 △A\triangle A△A 包含 △B\triangle B△B 那么 C△A≥C△BC_{\triangle A}\ge C_{\triangle B}C△A​≥C△B​ 。

而巧妙的是,距离 “直达航线” 最近的点都是合法中转点(如果不合法,边上的那个阻挡点就距离更近了)。所以其他的中转点必须避开它们。称这些点为「标杆点」。

从 (0,0),(n,m)(0,0),(n,m)(0,0),(n,m) 分别引直线,交点与二者便形成了 “中转点、起点、终点的三角形” 。直线只能从两个相邻「标杆点」之间穿过去,否则就会包含。此时,底边 (0,0)(0,0)(0,0) 到 (n,m)(n,m)(n,m) 至少是 2L2L2L,空隙的大小是 LLL,根据中位线的性质,最多只会到达两倍远的地方(而且恰好是顶点)。

不难发现,其他所有点到达 “直达航线” 的距离一定是最短距离的整数倍。(如果没看出来,下面的数学公式也能说明这一点。)于是其他点距离 “直达航线” 至少是两倍,而这也是上文中「标杆点」以外的中转点恰好没用的下限。所以结论得证。

怎么求「标杆点」呢?大家都是解析几何的老手了,直线方程 −mx+ny=cn2+m2-mx+ny=c\sqrt{n^2+m^2}−mx+ny=cn2+m2​ 给出了距离为 ∣c∣|c|∣c∣ 的直线。不妨设 c>0c>0c>0 ,因为负数的情形(即 “直达航线” 的下方)就是中心对称的结果。显然 cn2+m2=gcd⁡(n,m)c\sqrt{n^2+m^2}=\gcd(n,m)cn2+m2​=gcd(n,m) 是使得 x,yx,yx,y 有整数解的最小 ccc 。

对上文的补充:由于 cn2+m2=kgcd⁡(n,m)(k∈Z)c\sqrt{n^2+m^2}=k\gcd(n,m)\;(k\in\Z)cn2+m2​=kgcd(n,m)(k∈Z) 才会有 x,yx,yx,y 的整数解,所以 c=kgcd⁡(n,m)n2+m2c=k\frac{\gcd(n,m)}{\sqrt{n^2+m^2}}c=kn2+m2​gcd(n,m)​ 。而最小距离就是 gcd⁡(n,m)n2+m2\frac{\gcd(n,m)}{\sqrt{n^2+m^2}}n2+m2​gcd(n,m)​,倍数关系得证。

然而「标杆点」可能仍然很多(比如 n=mn=mn=m 的情况)。这一步大家就都想得到了,「标杆点」在中间最好。毕竟「标杆点」到 “直达航线” 的距离相同(不妨设为 ddd),设 L=n2+m2L=\sqrt{n^2+m^2}L=n2+m2​,再设「标杆点」之一 (x,y)(x,y)(x,y) 满足
xn+my=Ltxn+my=Lt xn+my=Lt

也就是投影长度为 ttt,那么
ans=t2+d2+(L−t)2+d2ans=\sqrt{t^2+d^2}+\sqrt{(L-t)^2+d^2} ans=t2+d2​+(L−t)2+d2​

求导易知 t≤L2t\le\frac{L}{2}t≤2L​ 时单减,t≥L2t\ge\frac{L}{2}t≥2L​ 时单增。故只需要用 ttt 最靠近 L2{L\over 2}2L​ 的两个点求答案。

实现的时候,可以考虑「标杆点」的移动带来的投影长度改变,这是容易计算的。

复杂度 O(log⁡n)\mathcal O(\log n)O(logn) 即扩欧的复杂度。

代码

原题其实是 n,m≤106n,m\le 10^6n,m≤106 的。这样的好处是,可以避免一些 double\tt doubledouble 运算。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long int_;
inline int_ readint(){int_ a = 0; char c = getchar(), f = 1;for(; c<'0'||c>'9'; c=getchar())if(c == '-') f = -f;for(; '0'<=c&&c<='9'; c=getchar())a = (a<<3)+(a<<1)+(c^48);return a*f;
}inline int_ exgcd(int_ a,int_ b,int_ &x,int_ &y){if(!b){ x = 1, y = 0; return a; }int_ d = exgcd(b,a%b,y,x);y -= (a/b)*x; return d;
}int_ n, m;
double calc(int_ x,int_ y){return sqrt(1.0*x*x+1.0*y*y)+ sqrt(1.0*(n-x)*(n-x)+ 1.0*(m-y)*(m-y));
}
int main(){int T = readint();for(int_ x,y; T; --T){n = readint(), m = readint();int_ d = exgcd(m,n,x,y); x = -x;int_ mov = (-x)/(n/d)-1;x += mov*(n/d), y += mov*(m/d);double L = sqrt(1.0*n*n+1.0*m*m);/*double now = (1.0*x*n+1.0*y*m)/L;double add = (1.0*(n/d)*n+1.0*(m/d)*m)/L;mov = (L/2-now)/add;*/mov = (n*n+m*m-(x*n+y*m)*2)/((n/d)*n+(m/d)*m)/2;x += mov*(n/d), y += mov*(m/d);double ans = calc(x+(n/d),y+(m/d));ans = min(ans,calc(x-(n/d),y-(m/d)));ans = min(ans,calc(x,y)); // 3 pointsif(d == 1) ans = L; // dirrectly arriveprintf("%.16f\n",ans);}return 0;
}

[CF_GYM102900L]Traveling in the Grid World相关推荐

  1. 安卓开发 高德地图定位的封装 十分钟上手

    前言 地图作为开发中三方sdk中较常遇到的一项,集成起来并不麻烦但是不小心踩坑可能会浪费较多时间,如果项目中多处使用还容易造成代码大量冗余,今天我们来将高德地图定位功能集成一个功能化模块,只需两分钟应 ...

  2. JAVA的静态方法的运算_java. util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作。...

    java. util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作. /* public static double abs ( double num):获取绝对值 ...

  3. Grid Coloring(AtCoder-2687)

    Problem Description We have a grid with H rows and W columns of squares. Snuke is painting these squ ...

  4. spiral grid

    spiral grid 时间限制: 2000 ms  |  内存限制: 65535 KB 难度: 4 描述 Xiaod has recently discovered the grid named & ...

  5. 使用NVIDIA GRID vPC支持视频会议和算力工具

    使用NVIDIA GRID vPC支持视频会议和算力工具 随着2020年的发展,远程工作解决方案已成为许多人的新常态.企业正在寻找行之有效的解决方案,如虚拟桌面基础设施(VDI),以使他们的团队能够在 ...

  6. CSS grid 的用法

    grid 的用法 加三个宽度为 200px 的列. .container {display: grid;grid-template-columns: 200px 200px 200px; } 用 fr ...

  7. mvc4 ajax grid,mvc4中用上一种grid

    view 视图@modelIEnumerable@using(Html.Configurator("The grid should...").PostTo("FirstL ...

  8. datagrid底部显示水平滚动_DevExpress WPF v19.1:Data Grid/Tree List等控件功能增强

    行业领先的.NET界面控件DevExpress 日前正式发布v19.1版本,本站将以连载的形式介绍各版本新增内容.在本系列文章中将为大家介绍DevExpress WPF v19.1中新增的一些控件及部 ...

  9. CUDA中grid、block、thread、warp与SM、SP的关系

    首先概括一下这几个概念.其中SM(Streaming Multiprocessor)和SP(streaming Processor)是硬件层次的,其中一个SM可以包含多个SP.thread是一个线程, ...

最新文章

  1. 电子科技大学计算机网络实验,计算机网络实验电子科技大学.doc
  2. 查找数组中未出现的和出现2次的数值 Set Mismatch
  3. OpenCV检测面部特征点的实例(附完整代码)
  4. HDU 5514 Frogs 欧拉函数
  5. EXCEL小技巧:如何统计非空单元格
  6. 她花了8个月让骗子爱上自己,然后把骗子引到警察局......
  7. 【计算机网络复习 物理层】2.1.3 码元、波特、速率、带宽
  8. 95-290-060-源码-内存管理-HeapMemorySegment
  9. signature=01a8bb5f15835faa2985256d36b2fe94,Point of Maintenance
  10. PERL 使用IO::Socket::INET模块实现socket编程
  11. K8S集群模式下fluent-bit日志收集方案设计和实践
  12. php搭建聊天室,php聊天室_用PHP MySQL搭建聊天室
  13. windows10搭建DVWA靶场(新手向)
  14. 漫步微积分二十二——微分方程和分离变量法
  15. G++’s Family
  16. 软件测试颗粒度,测试用例之度——系列之颗粒度(上)
  17. Matlab的插值与拟合
  18. 如何实现基于微信小程序的人脸识别
  19. 计算机二级 12月 地区,计算机二级各地区报名时间
  20. JAVA ffmpeg 视频处理

热门文章

  1. 怎样清理苹果手机内存空间_手机资讯:苹果iPhone如何拒绝骚扰短信清理短信教程...
  2. H264码流中SPS的获取
  3. Win10正式版Guest来宾账户开启使用方法
  4. python将学生信息保存到文件中_Python学生管理系统-文件保存版
  5. 分析的意义:数据背后的故事(1)
  6. c# word文档基本操作 (上)
  7. java中String转Long类型
  8. java的基本概念:进制、单位、编码、数据类型、变量声明、ASCII码
  9. CENTOS上的时间/时区设定
  10. Unix Domain Sockets