1 条题解
-
0
题解:E. And Constraint
题目理解
我们有两个序列:
- (长度 )
- (长度 )
可以进行的操作:每次选择任意 增加 ,花费 次操作。
目标:用最少操作次数使得对所有 满足:
其中 是按位与运算。如果不可能,输出 。
核心难点
- 操作只能增加 ,不能减少。所以初始 是下界。
- 约束 是位级约束。
- 操作次数最小化 = 让 尽量小,但又必须满足所有与约束。
位运算性质
对任意两个数 :
$$x \& y = z \quad \Rightarrow \quad z \le x \text{ 且 } z \le y $$并且 的二进制位必须是 和 都有的位。
更关键:若 ,则:
- 若 的某一位是 ,则 和 的这一位都必须是 。
- 若 的某一位是 ,则 和 不能同时在这一位为 (可以一个 一个 ,或两个 )。
动态规划思路
标程使用了按位构造的 DP。
状态定义
设 表示:在考虑前 个 值且满足前 个与约束后, 可能取的值以及达到该值的最少操作数。
但 范围很大(),不能直接枚举。标程技巧:
只枚举 可能的值,这些值由 、 和 的初始值决定。
关键观察
固定 和 需要满足:
对于 ,它必须同时满足:
- 与 的与等于
- 与 的与等于
所以 的二进制位受两个方向约束。
标程采用了从左到右递推,每个 只依赖于 和 。
转移方法
标程中的核心循环:
for(int i=1;i<=n;i++){ int x=0; g.clear(); for(int j=30;j>=-1;j--){ int y = x | a[i-1] | a[i]; if(j!=-1) y |= (1<<j); if(y >= b[i]){ ll mn=inf; for(stu l:f){ if((l.x & y) != a[i-1]) continue; mn = min(mn, l.dp + y - b[i]); } if(mn<inf) g.push_back((stu){y,mn}); } x |= ((1<<j) & b[i]); } swap(f,g); }解释:
-
:当前已经确定必须为 的位(来源于 的初始值)。
-
从高位到低位( 到 )枚举:
- 尝试在 中设置或不设置这位(当 时表示不设置任何新位)。
- 必须包含 和 的所有 位(因为 和 都要求 在这些位为 )。
- 如果 (不能减少,只能增加),则 是一个可能的 新值。
- 从上一层的 中找出所有 值 满足 ,计算操作数增量 ,取最小值。
- 加入 作为这一层的可能状态。
-
逐步累加 的当前位,确保我们考虑了所有可能的 。
为什么这样枚举是充分的?
因为 只能从初始值 开始增加,且增加的位只能从 变 。
$$b_i \ge b[i] \quad \text{且} \quad b_i \ \&\ a_{i-1} = a_{i-1} \ \text{且} \ b_i \ \&\ a_i = a_i $$
所有可能达到的 必须是:即 必须包含 和 的所有 位。
标程中的枚举方式,从高位到低位尝试设置 或 ,覆盖了所有满足 且包含 所有 位的值。
初始化和最终答案
- 初始 只有一个状态: 为 (虚拟前驱),操作数 。但注意第一个约束是 ,所以 需要包含 。
- 最终 时, 中存储所有可能的 值及其最小操作数。取最小 值即为答案。
- 若 为空,输出 。
复杂度分析
- 每个位置最多枚举约 种 ( 从 到 ,共 次)。
- 每次需要遍历上一层的 大小,但 大小不会超过 (因为每个 都不同且数量有限)。
- 总复杂度:,对于 可接受。
样例验证
以第一个样例为例:
n=4 a=[1,4,4] b=[1,2,3,4]过程:
- 可能值:包含 且 ,最小为 。
- 需要包含 ,且 ,并满足 。尝试得 是可行且最小的,操作数 。
- 继续推导得 ,,总操作数 。
代码实现要点
- 用结构体
stu{int x; ll dp;}存储状态。 - 设置为 以统一处理边界。
- 使用
inf表示不可达。 - 注意位运算优先级。
总结
本题的关键在于:
- 利用按位与的约束将 的可行值限制在较小的集合中。
- 从高位到低位贪心枚举 的可能取值。
- 动态规划记录每个位置每种取值的最小操作数。
- 由于位数 ,状态数 ,复杂度可行。
这是一个巧妙的按位构造 + DP 的题目,适合练习位运算与状态压缩思想。
- 1
信息
- ID
- 7134
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者