ABC 219
A
签到
B
签到
C
签到
D
背包
E
\(4*4\)的网格里有一些村庄,画一些连续的平行于边界的护城河,把所有村庄包围起来,求方案数
解:
非常秀的思路
二进制枚举每个点是否被护城河覆盖
判断每一种情况是否满足以下两个条件:
(1)每个村庄都被覆盖
(2)相同覆盖情况的连通块只有两个
为了满足第二点条件需要在原枚举情况下外围加一圈没被覆盖的格点,然后用并查集维护
F
读取长度为\(n\)的\(L,R,U,D\)指令\(k\)次,求经过的不同格点数
解:
这,非常离谱
假设第一轮走过的点集为\(V_1=\{(x_1,y_1),(x_2,y_2)…(x_n,y_n)\}\)
设\(a=x_n,b=y_n\)
那么第\(i+1\)轮走过的点就是\(V_{i+1}=\{(x_1+ia,y_1+ib),…,(x_n+ia,y_n+ib)\}\)
所以我们可以把整个过程看作\(n\)条斜率均为\(\frac{b}{a}\)的直线,但是这些直线可能有交集,如
\((x_i-x_j,y_i-y_j)=d(a,b)\),那么在\(d\)步后,两条直线就会相交
因为每个点的贡献是\((d_i,k)\),\(d_i\)表示第\(i\)个点走最少\(d_i\)步就会和其他点相遇
计算\(d_i\),我们可以对于每条直线找到一个顶点\((x_0,y_0)\)
令\((x_i,y_i)=(x_0,y_0)+d_i(x_0,y_0),(x_j,y_j)=d_j(x_0,y_0)\)
将\((x_0,y_0)\)相同的点放进同一个\(vector\),然后用差分求两个点之间的差值
G
\(n\)个点\(m\)条边的图,一开始第\(i\)个点上有数字\(i\),每次选择一个点\(k\),把相邻的点上的数字都改成点\(k\)上的数字,问\(m\)次操作后每个点上的数字。
解:
图上根号分治
设\(cnt=\sqrt{m}\)
每个操作前先用周围度数\(cnt\)的节点的标记更新自己
对于操作度数小于\(cnt\)的节点,暴力更新周围节点,复杂度\(O(\sqrt{m})\)
对于操作度数大于\(cnt\)的节点,给自己打一个标记,复杂度\(O(1)\)
因为度数大于等于\(cnt\)的节点最多有\(\sqrt{m}\)个,每个用标记更新自己的复杂度是\(O(\sqrt{m})\)
H
有\(n\)根蜡烛,第\(i\)根蜡烛在\(x_i\),长度为\(h_i\),每秒燃烧一个长度
一开始你在\(0\)处,路过一根蜡烛时可以吹灭它
最多剩下多少长度的蜡烛?
解:
代价提前计算\(dp\),跪了
我们首先可以认为:蜡烛可以燃烧成负数,这样方便提前计算代价
然后再加上一个条件:我们可以选择一些蜡烛不要它的长度,在此基础上求得到蜡烛的最大值
首先一个想法是加一根位置为\(0\),长度为\(0\)的蜡烛
我们定义\(dp[l][r][k][0/1]\)表示当前已经处理\([l,r]\)区间内的蜡烛,还能取\(k\)根蜡烛,现在在区间的左侧/右侧
那么每走一步,实际上我们损失掉的蜡烛长度是\(k\),比如从\(x_r\)走到\(x_{r+1}\),要减少\(k*(x_{r+1}-x_r)\)的长度,这样就方便了我们计算代价
\(dp\)方程为
左侧同理
然后再用左右两侧互相更新一下