AtCoder Beginner Contest 213
E - Stronger Takahashi
题意
给出一个迷宫: .
代表可以走的道路,#
代表墙,你可以花费一点力气打破任意一个 2×2 区域中的所有的墙
请问从迷宫的左上角走到右下角,最少要花费多少力气?
思路
这道题相比F题要水多了,但我并没看出来
这题可以相当于建图跑最短路,但由于图上的边权只有0和1,所以只需要用BFS就能完成,这就是01BFS
01BFS通过维护双端队列,使得队头元素是单增的,如果当前使用边权为0的边进行的松弛操作,那么把新的顶点push到队头,否则就是用边权为1的边进行的松弛操作,把新的顶点push到队尾
如此操作,可以保证队列中的元素都是形如00…0011…11…
关于这道题,考虑当前在格点T
那么*
都是可以通过花费一次力气到达的格点,而不需要力气到达的格点只有和T相邻的4个格点并且它们是.
则时间复杂度为 O(21NM)
点击显/隐代码
F - Common Prefixes
题意
定义字符串函数 f(S,T) 为字符串 S,T 的最长公共前缀,也就是LCM
给出一个长度为 N 的字符串 S,Si 表示从 S 的第 i 个字符开始的 S 的后缀
如abcd
中 S2=bcd,S3=cd
对于每个 k=1,…,N 求 f(Sk,S1)+f(Sk,S2)+…+f(Sk,SN)
思路
比赛时速度还是太慢了,对SAM还是不够熟练,由于公共前缀不好处理,考虑转为公共后缀,只需要将字符串反转后,倒序输出答案即可
那么 ∑i=1Nf(Sk,Si) 就是求字符串 s1s2…sk 的每个后缀在 S 中的出现次数
这个问题使用后缀树很容易解决,用sz数组代表SAM中每个顶点right集合的大小,mx数组表示该顶点的right集合中的最大长度
先找到 Sk 对应的节点 p,然后暴跳 prt 数组,那么以 sk−mx[p]+1…sk 在 S 中的出现次数就是 sz[prt[p]]−sz[p]
那么顶点 p 对答案的贡献就是 mx[p]⋅(sz[prt[p]]−sz[p]),求和即可
但是如果对每个节点都暴跳 prt 数组复杂度是 O(N2) 肯定超时,所以还需要记忆化一下
记 dp[p] 为顶点 prt[p] 产生的贡献,不记当前顶点 p 产生的贡献,是因为当前顶点的贡献会和它的而自己顶点的sz大小有关
时间复杂度为 O(N)
点击显/隐代码