【比赛】【SMOJ 2019.3.3】
十 年 O I 一 场 空 , 开 错 题 目 见 祖 宗 。
\(\mathrm{T1}\)
原来时间复杂度\(\Theta(6*10^8)\)的程序竟然能在\(4s\)之内跑完。
如没有括号限定的话,\(\mathrm{P}\)表示的是一个格子被一个矩形覆盖的概率。
-
暴力推公式(\(\mathrm{P+(1-P)P+(1-P)^2P+(1-P)^3P......}\))
\(80\ pts\)(精度被卡)
-
优化
\(\mathrm{P(\texttt{至少有一次选中}) = 1-P(\texttt{一次都没有被选中})}\)
所以上面的式子可以转化成
\[\mathrm{1-P^{time}} \](\(time\)表示矩形个数)
这样直接搞有\(90\ pts\)。(精度依然会被卡)
然后就会想到快速幂(因为这样做乘法次数更少,精度丢失的也更少,
时间复杂度反倒是其次的)。把\(90\ pts\)做法里面的\(\mathrm{P^{time}}\)用快速幂实现就可以\(\mathrm{AC}\)了。
中间那一段可能有些长,其实就是用容斥原理计算一个点不被覆盖的概率。(算出四边,再减去四个角)
\(\mathrm{T2}\)
原来这就是多校联考题的真实水平。
首先我们可以发现对于一个建筑物,它的每一列都是独立的,所以我们可以先\(\mathrm{DP}\)每一列,再\(\mathrm{DP}\)整个场地。
然后因为每种颜色可以分开算,所以下面的题解默认只算看到蓝色的建筑物的方案数。
1.\(\mathrm{\Theta(n^8)}\)做法
设\(\mathrm{f[r][H][R][G][B]}\)为对于每一列,前\(r\)排放了\(\mathrm{R}\)个红色正方体,\(\mathrm{B}\)个蓝色正方体,\(\mathrm{G}\)个绿色正方体,且这一列方块的最高高度为\(\mathrm{H}\)的摆放方案数。
则我们可以每次考虑放多一整排进去,状态转移应该是这样:
\(\mathrm{\begin{cases} f[r+1][H][R+R'][G+G'][B+B'] = P(R',G',B') \times f[r][H][R][G][B] & (R'+G'+B' \leqslant H) \\f[r+1][R'+G'+B'][R+R'][G+G'][B+B'] = P(R',G',H-R'-G') \times f[r][H][R][G][B] & (R'+G'+B'>H) \end{cases}}\)
- (上面的式子当中,第一种情况是\(R'+G'+B' \leqslant H\);第二种情况是\(R'+G'+B'>H\)。)
- \(\mathrm{P(x,y,z)}\)表示三类数量分别为\(x,y,z\)的元素集的可重集排列数。
- 第二条式子中出现\(\mathrm{P(R',G',R'+G'+B'-H) }\)是因为突出去的那些高于\(\mathrm{H}\)的正方体必须是蓝色,所以不用于计算可重集排列。
每一列算好之后就可以直接算整个场地的了。
用\(\mathrm{F[l][R][G][B]}\)表示前\(l\)列,且用了\(\mathrm{R}\)个红色立方体、\(\mathrm{G}\)个绿色立方体、\(\mathrm{B}\)个蓝色立方体的方案数。
然后每次枚举上一列的\(\mathrm{RGB}\)即可。
坑点:
- 弄错数组的下标
- 逆元写错(当然其实可以直接写组合数)
- 把\(\mathrm{H-R'-G'}\)写错了……(不知道为啥写成了\(\mathrm{R'+G'+B'-H}\)……)
2.\(\mathrm{\Theta(n^6)}\)做法
其实我们可以放飞一下思想,把红色和绿色这两种颜色混合起来。
这样的话,在求\(f\)数组时我们就可以少枚举一个颜色,也就是少了两层循环了(每个颜色还要再枚举上一层的颜色个数)。
这样算出来的答案当然是错的,但是我们只要加上一步就对了:
把最终答案乘上\(\mathrm{C_{R+G}^{R}}\)(当然也可以乘上\(\mathrm{C_{R+G}^{G}}\))。
在知道红绿两种颜色的位置有多少不同方案之后,再乘上红绿颜色分布的组合数就是最终答案了。
时间复杂度\(\Theta(n^6*case)=\Theta(19.2\times 10^8)\),卡卡常数就可以过了。
坑点:数组没有开两倍!!!数组没有开两倍!!!数组没有开两倍!!!
但是,其实不需要卡常的。
我们并不需要每次都重新计算一次\(f\)数组,这个数组完全可以\(\Theta(n^6)\)预处理好,然后每次再像之前那样直接对\(\mathrm{F}\)数组进行\(\mathrm{DP}\)。
这样的话,时间复杂度就变成\(\Theta(n^6+case\times n^5)=\Theta(10.54\times 10^8)\),亲测不需要卡常,可以直接过。
\(\mathrm{T3}\)
这一题倒在了建边上。
就是说,如果两个好点中间有很多好点的话,应该怎样确定这两个点之间至少应该加几个好点?
其实不需要想这么多,只需要点与点之间两两建边,边权是两个点之间的曼哈顿距离-1即可(如果两点之间要增加的好点数量可以更少的话,就一定可以通过走两点之间的其他好点来解决)。
然后在建边时特判一下这条边的两个端点是否在同一个位置上即可。
最后还要特判一下起点和终点是否在同一个位置。
话说为什么堆优化的Dijkstra会错,直接Dijkstra就对呢?
虽然直接搞的确快很多……