1 条题解
-
0
题目重述
我们有两个长度为 的数组 和 ,元素范围 。
定义好对 (good pair) :可以通过任意次以下操作将 变成 :
选 ,以及非负整数 ,做:
我们允许两种移动:
- 选 ,
- 选 ,
可以超过 。
问:最少移动次数,使 成为好对。
第一步:好对等价条件
这个操作的特点是:
- 对 做 AND 只能清除某些 1 位
- 对 做 OR 只能设置某些 1 位
- 两个操作同时发生,且 任意
经过推导(见题解或结论),好对等价于:
-
显然成立(不需要操作)或者
-
存在 使得 是 的子掩码
即 ( 的所有 1 位在 中也是 1)
为什么?
如果 中有这样的子掩码对,那么可以选 等,反复操作让 变成 。反之,如果没有这样的对,则 无法变到 (证明略)。
第二步:最少移动次数分解
我们只能增加元素,所以最终数组元素 原始值。
情况 1:最终
移动次数:
因为如果 ,需要增加 共 次;
如果 ,需要增加 共 次。
情况 2:最终 中存在子掩码对
我们只需要考虑修改 (因为一旦 满足条件, 可以通过操作任意匹配 ,无需额外移动)。
目标:选两个不同下标 ,增加 到 ,使得 是 的子掩码,且增加值之和最小。
即:
$$\text{cost}_2 = \min_{i \neq j} \min_{\substack{b'_i \ge b_i \\ b'_j \ge b_j \\ b'_i \& b'_j = b'_i}} \big( (b'_i - b_i) + (b'_j - b_j) \big) $$
第三步:图论模型
构造图 ,顶点为 到 (可能超过 但不超过 )。
边:
- ,权重 (模拟 操作)
- ,如果 是 的子掩码,权重 (因为可以一步操作实现)
那么,从 到 的最短路径长度 表示:
将 增加到某个值,再跳到 的子掩码(或反过来),最小增加值之和。注意:我们需要的是两个不同源点之间的最短路径。
第四步:多源 0-1 BFS / DP 实现
我们维护每个顶点 的两个最近源点(及其距离):
dist1[u],id1[u]:最近源的距离和编号dist2[u],id2[u]:次近源的距离和编号
初始化:
每个 作为源,dist1[b_i] = 0,id1[b_i] = i。
如果 重复出现,则dist2立即为 0。传播分三阶段(保证所有最短路径被找到):
-
向上传播( 边)
从小到大遍历 ,用 更新 :- 如果
dist1[u]+1 < dist1[u+1],则替换 - 否则如果
dist1[u]+1 < dist2[u+1]且id1[u] != id1[u+1],则更新次近
- 如果
-
子掩码传播( 边)
从大到小遍历 ,枚举 的所有子掩码 :- 用
dist1[u]更新 - 注意不同源
- 用
-
向下传播( 边)
从大到小遍历 ,用 更新 (因为可以反向走 来模拟 到别的值)
每次更新时,如果
id1[u] != id1[v],则更新dist2。最终答案:
$$\text{cost}_2 = \min_{u} \big( \text{dist1}[u] + \text{dist2}[u] \big) $$
第五步:时间复杂度
- 顶点数
- 枚举子掩码总复杂度 (每个数的子集个数平均 )
- 传播
- 总复杂度 ,可过
第六步:最终答案
第七步:代码实现要点
- 注意 可达 ,数组开 足够
- 枚举子集:
sub = (sub-1) & u - 用
INF表示无穷大 - 重复值直接输出 (因为 已满足条件)
结论
本题的核心是:
- 发现好对等价于数组相等或 中有子掩码对
- 将问题转化为图上多源最短路径问题
- 用 DP 维护最近和次近源
- 通过三阶段传播保证找到所有可能的最小增加值
- 1
信息
- ID
- 6361
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者