abstract:
- V const & a 加速
F. Mirror
题意
链接
问题:
有n个人在y=0的平面上(及xoz平面)。z=0平面上有一面镜子(边平行于坐标轴)。z=a平面上有q个点(保证a大于所有人的z坐标)。 所有人面朝镜子,且在镜子和q个点之间(即每个人的z坐标保证0 问对于某个点,让所有人能够通过镜子看到那个点的镜子的最小面积。
题解
三维几何+镜像+凸包
首先考虑镜面,我们可以通过(初中科学的)镜面反射原理,关于z=0做出z=a的对称平面z=-a。问题就变成了n个人看z=-a上的某个点。(下图绿点是人,红点是询问点)
然后观察,镜子的高和宽是独立的。 于是我们分别求它们的最大值即可。
求高比较简单,我们朝-x方向看yoz平面。通过把每个人跟点Q的像Q‘相连,我们发现离Q’z轴距离最近的人对应着镜子的下边界,最远的人对应着上边界,通过维护所有人z坐标的max_z&min_z以及相似三角形可以直接求出两个边界,复杂度为O(1)。
我们用同样的方法,朝-y方向看xoz平面。 通过把每个人跟点Q的像Q‘相连,我们发现,左右边界并不对应着最左边与最右边的人。而且随着询问点的变化,对应着左右边界的人也在变化。
如果我们暴力的找对应左右边界的人,复杂度为n*q ,不可行。
我们发现,对应着左右边界的人虽然随着询问点变化,但他们都在凸包上(如下图)。
更进一步,如果我们将询问点按照x坐标排序,随着询问的x坐标增加,左右边界的人在凸包上的变化是顺时针旋转的。(考虑你从左到右观察一个正前方的凸包)
于是我们就能够通过一个nlogn的凸包预处理然后O(1)地回答每个询问,复杂度为O(q+nlogn)
剩下的是实现”从左到右看凸包时凸包左右边界的顺时针更新“。
首先是写out,in函数(右手法则,向外转就是逆时针),用来逆时针、顺时针遍历凸包上的点。因为极角排序凸包存的点是逆时针的(极角排序的那个角是与y轴的逆时针夹角。),所以out就是++。
先找到凸包的下上顶点,作为初始的左右边界的对应点。
然后根据x坐标从小到大枚举询问点Q。
对于每个Q,不断顺时针更新左边界对应的人,直到他与Q的连线在他凸包上顺时针的下一个人与Q的连线的外面(直观上显然正确)。 右边界同理。
某些编辑器比如codeforces不能混用iostream与stdio
代码
#include
#include
#include
#include
#include
心路历程
当有两个以上的bug时你就炸了
wa0:FAST_IO codeforces以用就wa
wa1:输出rep(i,1,q) not rep(i,1,n)//最后才发现
wa2:凸包板子里面下标从0开始。
Problem F Fair Chocolate-Cutting
题意
来源:ICPC Asia Regional Contest, Yokohama, 2018–12–09
让你求所有平分凸多边形的线段中最长和最短的那两条。
输出它们的长度。
---
题解
证明题+硬核平面几何
我们有结论:(目前不会证明)
某合法(平分多边形的)线段的端点在顶点上时一定是局部最长或最短的。
除此之外,当某合法线段垂直于任意“外角”平分线时,也是局部最短的
于是问题就转化成
1.对于每个顶点,找到过它的合法线段。
2.对于每个角(跳过一些线段的“相邻”两条线段的延长线交出的角),找到垂直它的平分线的合法线段。注意特判掉角不存在的情况,即两边平行。
对于1,只要从该顶点开始不断逆时针扫顶点,直到刚刚超过1/2的总面积。然后把上一个三角形分割一下。
对于2,直接用平面几何知识以及三角函数求解
---
代码
#include
#include
#include
#include
#include
#include
心路历程
关键是不会证明。
复数大法好啊!!!(其实还是慢5倍??下面那题)
B. Ali and Wi-Fi
题意
来源ACM International Collegiate Programming Contest, Tishreen Collegiate Programming Contest
100个圆,每个圆代表wifi覆盖区域,每个wifi有一个网速。你最多可以连入m个WiFi,网速为这些wifi的总和。
问你最大的网速是多少。
题解
想法题+圆模板
我们知道n个圆最多可以把平面分成n^2-n+2个区域(递推进阶题233)。所以可以考虑遍历每个区域,计算它被哪些圆。。。
我们发现维护一块区域很难,而要取最大的m个更难考虑。
于是考虑维护圆与圆的交点。我们发现每个区域都是圆交出来的,i.e.交点都在区域的边界上。
于是我们可以枚举交点来代替枚举区域,显然交点个数也是n^2级别的。(考虑圆内含的情况,所以要把每个圆心也枚举一遍)
这样枚举的另一个好处是可以很简单地处理m:
枚举每个交点,计算有几个圆包含它。然后直接在这些圆中取最大的m个。
复杂度为n^2nnlogn。
如果我们用优先队列来维护最大的m个,那么复杂度里可以去掉一个n。
代码
#include
#include
#include
#include
#include
心路历程
没初始化。
瞎debug发现long double int求和会爆精度。
priority_Q太久没用,忘记pop是从头上弹出的了orz。
vector 和对于1e6的数据其实只比数组慢10ms。