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\) 数据),也可以轻松通过:

  1. 将所有的 vector 换成数组。
  2. 使用数组堆(可以使用 \(\rm STL\) 中的 make_heappush_heappop_heap 简化写法,具体使用方法可以自行搜索)。
  3. 注意到每个重链都是一个线段树,于是不要以 \(1\sim n\) 建立线段树,求的时候有空间破坏了,每个重链搞一个动态开点线段树。
  4. 开始的时候线段树为了方便丢了一个 pair 进去比较大小的时候计算位置,有点浪费,于是可以直接重载运算符,比较编号,这样只要一个数即可。
posted @ 2022-05-27 22:13  Werner_Yin  阅读(232)  评论(0编辑  收藏  举报