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 ):

题面里这个例子即道路与城市碰撞。
也就是说,只能是道路与某个城市碰撞。
不难发现答案:

设当前询问点 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\) 的时候,可能会有这三种情况 :
 
此时即是两个建筑碰撞的情况。不难发现,此时需要满足的是,
\(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 的代码和提交记录:
可以看到,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]\) 的值。
这样也许可以卡卡常?不知道,没试……
写在最后:
我永远喜欢幽幽子大人!~

浙公网安备 33010602011771号