CF1167G Low Budget Inception 题解

观前提示:本题中的 d 绝对不是没有用的!牢记这句话!


题意概览

给定在一个数轴上分布的 n 个建筑,每个建筑被抽象为 1*1 的正方形。

给出相邻建筑物的最大距离 d。

给出 m 个询问,输出每次询问中,在 \(x_i\) 处将 \(x_i\) 右侧数轴逆时针翻折后可以得到的最小的最终角度 ( 后文记作 \(\phi\) ) ,使得任意两个建筑或任意一个建筑与道路不重叠。

数据范围

\(1\leq n \leq 2 \ \cdot \ 10^5\) , \(0 \leq d \leq 7000\),

\(a_i=0,0<a_{i+1}-a_i \leq d+1\),

\(0\leq x_i \leq a_n +1,x_i < x_{i+1}\),

要求输出与标答不超过 \(10^{-9}\)。


下面是逐步的分析


Step 1,101 points

题目到手第一步,观察可否最基本的暴力,发现不可写。不写了

那么直接开始推性质。

从最基本的 n=1 开始:

n=1, 也就是只有一个城市的情况,或者说最终状态是道路与城市碰撞的情况 ( n>1 ):

题面里这个例子即道路与城市碰撞。

也就是说,只能是道路与某个城市碰撞。

不难发现答案:

![]( https://cdn.luogu.com.cn/upload/image_hosting/zk0cunb6.png?x-oss-process=image/resize ,m_lfit,h_170,w_225)

设当前询问点 xi, 最近的正方形左下角坐标为 ai,

左右的情况合并,就是 \(arctan(\tfrac{1}{min(|xi-ai-1|,|ai-xi|)})\)。

类比,可得当 \(x_i \leq a_1\) 或 \(x_i \geq a_n\) 的时候,也是这个答案。

而对于 \(a_1 \leq x_i \leq a_n\) 的时候,可能会有这三种情况 :

![]( https://cdn.luogu.com.cn/upload/image_hosting/9j8yu17v.png?x-oss-process=image/resize ,m_lfit,h_170,w_225) ![]( https://cdn.luogu.com.cn/upload/image_hosting/jusf8a6a.png?x-oss-process=image/resize ,m_lfit,h_170,w_225)![]( https://cdn.luogu.com.cn/upload/image_hosting/704j5kwk.png?x-oss-process=image/resize ,m_lfit,h_170,w_225)

此时即是两个建筑碰撞的情况。不难发现,此时需要满足的是,

\(x_i-a_l-1=a_r-x_i\)

\(x_i-a_l-1=a_r-x_i+1\)

\(x_i-a_l=a_r-x_i\)

中的任意一个

其中 al 表示 xi 左侧最近建筑的左下角横坐标,ar 表示 xi 右侧最近建筑的左下角横坐标,

式子也不难推出。

而要想找到对应的两个城市,只需要两个指针,一个指向左侧,一个指向右侧。当扫到的两个城市不满足碰撞要求时,就向外扩展,哪边指针离 xi 离得近就拓展哪边。

下面是 101 points AC 的代码和提交记录:

CF 提交记录

可以看到,102 的地方 TLE 了。


那么接下来就是优化了,显然直接卡常不是个好习惯。

那么,再回想起开头那句话:

观前提示:本题中的 d 绝对不是没有用的!牢记这句话!

接下来,就是带上 d 的优化。


Step 2,127 points AC

考虑为什么会 TLE ,单纯看思路的话,其实很快就能扫到两城市相碰的最终辐角,或辐角过小以至于最后是道路与城市碰撞的情况。

但是很显然,左右的枚举端点是有一个界限的,也就是 “城市之间过远”。

那么既然都想到这里了,不难发现,由于每两个城市之间的距离都小于等于 d+1,那么道路与城市的碰撞最小辐角就是 \(arctan(\tfrac{2}{d})\) ,不难推出实际边界约是 :

\([ x_i-2 \cdot min(a_r-x_i,x_i-a_l)-1,x_i+2 \cdot min(a_r-x_i,x_i-a_l)+1 ]\)

这样一来,虽然输入的 d 确实没有用上,但是对于相邻城市的距离 \(d_i\),

我们可以把每次暴枚区间长度缩小到“左右城市坐标差最大仅\(2d_i\)”。

这样可以更进一步在不用 bitset 的情况下跑出更快的时间。

最后的 CF AC记录,最慢的点跑了 900ms 左右。


Step 3,也许没用的优化思路

再次考虑到代码中调用了相当多的 atan(),也许可以提前预处理出所有需要用到的 atan() 函数值,因为每一次调用中,传入参数的分子都是 1,也就是说只用记录 \(arctan(\tfrac{1}{x}),x\in [1,2 \cdot d]\) 的值。

这样也许可以卡卡常?不知道,没试……


写在最后:
我永远喜欢幽幽子大人!~

posted @ 2022-10-11 10:53  Fy5枫叶  阅读(65)  评论(1)    收藏  举报