题解 P5397 [Ynoi2018] 天降之物

毒瘤卡常题。

考虑分块。先想查询。

对于块的内部,每个块预处理 disi,j,k,表示第 i 个块内,jk 的最短距离。这里得把 j,k 在块内离散化,因为块长 O(n),最多出现 O(n) 个值,空间是 O(nn) 的。

对于块到块,不难发现对于同一个值,仅每个块最靠左的位置和最靠右的位置才可能是优的。所以维护 Li,jRi,j 分别表示第 i 个块,值为 j 最早出现位置和最晚出现位置。每个块扫一遍,贪心算一下即可。

想想修改。对于 x 变成 y 的修改,遍历所有整块。

  • 若当前块没出现 x,直接跳过。

  • 若当前块没出现 y,直接将 x 对应的离散值传给 y

  • 若当前 x,y 均出现,暴力更新关于 x,y 所有信息。因为每次这样修改都会使块内的颜色少一,每次修改 O(n),最多修改 O(n) 次,共 O(n) 个块,所以时间复杂度还是 O(nn)

假设 n,q 同级,时空复杂度都是 O(nn) 的。

难点在于卡常。几个比较重要的优化。

  1. 表示真实值和离散值映射关系的 vis 数组和 dis 数组大小都是 O(nn) 的,且值域都是 O(n),可以开 short,空间常数能少一半,效果明显。

  2. 内存访问一定要连续。内存访问连续对常数影响巨大。令 vis 数组第一维表示值,第二维表示块的编号。其他数组都以块编号为第一维。

  3. L,R 数组以离散值为第二维,这样空间是 O(n) 的。

  4. disi,j,k 保证 j<k,且尽量少调用 dis,因为它内存访问相当不连续。可以把 i,j 压成一维,改为 si+j,我觉得效果不大。

  5. 随缘调调块长,我是 370

  6. 用 C++20,只有一两个点差几十毫秒可以多交几发,利用评测机波动,或者利用 O2 性质来一些无谓的循环(我感觉会快,可能是假的)。

我半个小时交了四页,要有持之以恒的耐心。

posted @   Terac  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示