UR #4
代码见 UOJ/UR#4 · yinjinrun/code-public-2 - 码云 - 开源中国 (gitee.com)。
UOJ51 【UR #4】元旦三侠的游戏
给出三个整数 \(a, b, n\),保证 \(a \geq 2\),\(b \geq 1\),\(a^b \leq n\)。两人轮流进行操作,每人每次可以选择将 \(a\) 的值加上 \(1\),或者将 \(b\) 的值加上 \(1\)。但是任何人操作以后都不能违背 \(a^b \leq n\) 这个条件,无法再进行操作的人就输掉了这一场游戏。
给定 \(n\),\(m\) 组询问,每次给出 \(a, b\),问先手是否必胜。
\(n \le 10^9, a^b \le n\)。
博弈论
动态规划
和官方题解不一样,希望不会被叉。
考虑对于朴素的 DP 进行加速,我们可以发现,每两轮考虑,前面一定是 \(a \gets a + 1, b \gets b+ 1\),直到不能进行此类操作,接着跑朴素的 DP + 记忆化即可。
为什么前面一定是 \(a \gets a + 1, b \gets b + 1\) 呢?考虑进行到最后,如果先手能必胜,那么在前面若干轮,不管后手的选择什么,先手始终选择对立的一个令 \(a \gets a + 1, b \gets b + 1\),然后可以拖到这个局面,最后获胜。
如果最后先手没有办法必胜,那么后手可以类似地进行对立的操作,还是将先手拖到这个局面,最后让先手输掉比赛。
于是可以简化一下状态数目了,最后对于 DP 记忆化一下,再加个对于 \(b = 1\) 的剪枝即可。
UOJ52 【UR #4】元旦激光炮
生蛋侠、圆蛋侠和零蛋侠分别有 \(n_a, n_b, n_c\) 个激光炮。生蛋侠的激光炮的威力分别为 \(a_0, a_1, \dots, a_{n_a - 1}\),圆蛋侠的激光炮的威力分别为 \(b_0, b_1, \dots, b_{n_b - 1}\),零蛋侠的激光炮的威力分别为 \(c_0, c_1, \dots, c_{n_c - 1}\)。满足 \(a_{i - 1} \leq a_i\),\(b_{i - 1} \leq b_i\),\(c_{i - 1} \leq c_i\)。
每次你可以问一个激光炮的威力,你需要告诉他们威力第 \(k\) 小的激光炮威力是多少。你最多可以询问 \(100\) 次。
对于所有测试点,\(0 \leq n_a, n_b, n_c \leq 10^5\),\(1 \leq a_i, b_i, c_i \leq 10^9\)。
交互
居然没有想到……
考虑令 \(t = \left\lfloor\frac{k}{3}\right\rfloor\),然后取出 \(a\) 的第 \(t\) 个,\(b\) 的第 \(t\) 个,\(c\) 的第 \(t\) 个,假设 \(a\) 的最小,那么我们可以排除 \(a\) 的前 \(t - 1\) 个元素,然后继续查找,每次 \(k \to \frac{2}{3}k\),用的次数为 \(3\),次数不超过 \(100\) 次。注意当 \(k \le 2\) 的时候暴力比较即可。
UOJ53 【UR #4】追击圣诞老人
给出一棵 \(n\) 个点的树,每个点有一个权值 \(w_i\),然后我们定义 \(i\) 可以到达 \(j\) 当且仅当 \(j\) 在 \(a_i, b_i, c_i\) 形成的最小连通块中,我们定义一条序列的权值为其 \(w_i\) 之和,一个序列 \(\{x_i\}\) 合法当前 \(x_i\) 能到达 \(x_{i+ 1}\),求所有合法序列中前 \(k\) 小的权值。
\(n,k \le 5\times 10^5\),保证答案 \(\le 10^8\)。空间 \(\rm 100MB\)。
树/树链剖分
数据结构/线段树
堆
卡常题。
看到题,这个可以类似于 \(\rm K\) 短路,直接左偏树!然后扣链直接搞一个线段树套可持久化左偏树!结果写到一半发现空间根本开不下/kk。
首先,最小连通块是好搞的,只有几个路径,在纸上面画一画就行了。\(k\) 不大,于是可以考虑一条一条从堆里面取出,然后进行拓展。关键是如何拓展,我们可以将所有路径拆成一条一条直上直下的链,每次相当于找到这个链里面的最小的点(可以树剖+线段树求出),然后:
- 将链断开,分成两条链,然后分别计算权值。
- 从这个最小的点后面加点。
实现并不困难。关键是卡常,给出几个卡常小技巧,让你即使有如我一样的大的时空常数(似乎这个题时空一起卡,还有恶心的 \(\rm HACK\) 数据),也可以轻松通过:
- 将所有的
vector
换成数组。 - 使用数组堆(可以使用 \(\rm STL\) 中的
make_heap
,push_heap
,pop_heap
简化写法,具体使用方法可以自行搜索)。 - 注意到每个重链都是一个线段树,于是不要以 \(1\sim n\) 建立线段树,求的时候有空间破坏了,每个重链搞一个动态开点线段树。
- 开始的时候线段树为了方便丢了一个
pair
进去比较大小的时候计算位置,有点浪费,于是可以直接重载运算符,比较编号,这样只要一个数即可。