Round D都要开始了, Round C还没搞定的我(D题不会搞)…另外300+名次也能拿到面试资格呢, 然而做的人却越来越少了.
Problem A. Monster Path
neta某手游…给个R*C
的矩形地图, 上面用.
和A
标注, 走到A
上有P
的概率抓到妖怪, 走到.
上有Q
的概率抓到妖怪. 当在一个位置抓过妖怪, 下次经过就抓不到了, 给定起点坐标Rs
和Cs
, 需要走一条路线使得走S
步获得妖怪数的期望最大, 求这个期望.
因为S
最大只有9
, 直接乱dfs每条路线就行了. 用数组记录一下当前位置没有抓过怪物的概率, 然后搜的时候每经过一个地点, 可计算出走这里抓到怪物的概率, 然后更新数组里当前位置没有抓过怪物的概率, 继续搜下去, 过程中记录一下概率和就是期望.
1 | //省略头文件 |
Problem B. Safe Squares
为啥我觉得这题比较难, 过的人却最多…
给一个R*C
的矩形, 给K
个矩形上的点, 求矩形上有多少个正方形不包含这些点中任意一个.
由于R
,C
,S
最大能到3000
, 所以需要向O(RC)
上靠, 自然会想到动态规划.
如果用dp[i][j]
表示前面i*j
的矩形中包含的正方形数, 则dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1]
表示前面i*j
矩形中不含当前点grid[i][j]
的正方形数量. 为了求得dp[i][j]
, 还需要加上所有以grid[i][j]
为右下角的正方形数量.
因为光枚举i
和j
复杂度就接近10^7
, 因此需要预处理以grid[i][j]
为右下角的正方形数量.
以grid[i][j]
为右下角的正方形数量等于以grid[i][j]
为右下角的最大合法正方形边长(从1
开始取, 每个长度都能找到一个合法的正方形), 问题变成了找上方和左方最近的非法点的距离. 这个依然可以用动态规划做.
如果dpDis[i][j]
表示以grid[i][j]
为右下角的最大合法正方形边长, 则dpDis[i][j]
要么被最接近的非法的grid[i-x][j]
限制, 要么被最接近的非法的grid[i][j-x]
限制, 要么和dpDis[i-1][j-1]
受到相同的非法点限制. 我们用left[i][j]
表示最接近的左边的非法点距离, top[i][j]
表示最接近的上边的非法点距离, 则有:dpDis[i][j] = min(top[i][j], left[i][j], dpDis[i-1][j-1])
.
其中left[i][j]
可以很容易根据left[i-1][j]
和当前位置点的合法性计算出来, top[i][j]
同理.
有了dpDis[i][j]
之后我们就可以完成之前的公式:dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + dpDis[i][j]
.
复杂度O(RC)
.
1 | //省略头文件 |
另一种计算dpDis[i][j]
的方法是通过二分.
用数字1
表示非法点, 0
表示合法点, 预处理数组sum[i][j]
表示矩形中1
的个数.
有了sum[i][j]
数组, 可以得到其中任意正方形中1
的个数. 如要得到以grid[i][j]
为右下角, 边长为L
的正方形内1
的个数, 可以用sum[i][j] - sum[i-l][j] - sum[i][j-l] + sum[i-l][j-l]
求得, 然后通过二分, 查找使得1
个数为0
的最大边长L
, 就是dpDis[i][j]
的值.
Problem C. Evaluation
给N
个形如a=f(b,c)
的字符串, 表示变量a
的值依赖b
和c
的值. b=g()
这样的字符串表示给b
一个基本值. N
不超过1000
, 左侧变量只会在左侧出现一次, 右侧函数内变量数不超过10
. 现在可以任意安排顺序, 问这些字符串能否使得每个变量都能够求得值(是否合法).
直接把每个变量名拿出来(想念js正则), 依赖关系用单向边连起来, 构成图. 如a
依赖b
和c
,则用c
和b
指向a
. 然后我们根据入度关系, 用拓扑序进行更新, 从有值的点向依赖他的点更新, 最后看看是否有入度不为0
的点(依赖成环)或者没有定值的点(如没有定义基本值). 复杂度为O(N)
(点数不会超过11*N
, 边数也不会超过10*N
).
看代码的时候需要注意的是, 我代码里面本意是用val[]
表示是否能求出值, 但实际上只要其依赖的变量中有一个能求出值, 其val[]
就会变成true
. 其需要入度计数cnt[]
辅助, 当val[]
为true
且入度为0
时才保证其依赖的数都已经有值了.
1 | //省略头文件 |
Problem D. Soldiers
彻底不会..看了份代码才想明白. 想到了就是SB题, 可惜智商不够..
给N
个士兵, 每个有一个攻击力A[i]
和防御力D[i]
, Alice和Bob轮流选且Alice先选, 每次选择的士兵攻击力或者防御力必须大于所有已经被选中的士兵, 直到不能选. 两人都身经百战, 见得多了, 问Alice是否能够比Bob多选一个士兵.
Alice多选一个士兵等价于先手走最后一步.
假设攻击力最高是x
, 防御力最高是y
, 可知当选择的士兵里有攻击力为x
和防御力为y
的士兵时就不能再选了.
如果有一个士兵的攻击力为x
防御力为y
, 则直接选他, 先手必胜.
如果没有这样的士兵, 则只有攻击力为x
且防御力小于y
的士兵和防御力为y
且攻击力小于x
. 对于这两类士兵, 每类至少有一个士兵, 先选到其中一个的人必败, 因为后手可以选另一类的任意一个使得先手无法再继续选择. 因此要避免先选A[i] = x
且D[i] < y
和A[i] < x
且D[i] = y
的士兵.
要避免这样的选择, 即要在A[i] < x
且D[i] < y
的士兵集合中走最后一步, 就形成了子问题.
整体复杂度O(n^2)
.
1 | //省略头文件 |