3022.给定操作次数内使剩余元素的或值最小
题目描述:
给你一个下标从 0 开始的整数数组 nums
和一个整数 k
。
一次操作中,你可以选择 nums
中满足 0 <= i < nums.length - 1
的一个下标 i
,并将 nums[i]
和 nums[i + 1]
替换为数字 nums[i] & nums[i + 1]
,其中 &
表示按位 AND
操作。
请你返回 至多 k
次操作以内,使 nums
中所有剩余元素按位 OR
结果的 最小值 。
数据范围:
$1\le nums.len \le 10^5, 0\le nums[i] \lt 2^{30}, 0\le k \lt nums.len$
题解:
按位考虑,而且需要从最高位开始考虑,如果这一位所有的 $1$ 可以在 $k$ 次之内处理,那么答案中这一位就可以为 $0$ 。而且这种替换操作其实就是一个区间操作,也就是有多少个 $1$ 吧,操作次数与 $1$ 的个数相同,但是全是 $1$ 的话就不行,实际就是一个贪心操作,只要与值为零,就下一段,不为零就需要操作次数。但是这样操作的时候剩余的位也被影响到了,次高位之类的还要考虑。
正确做法是,先考虑最高位,如果最高位可以在 $k$ 次之内处理完毕,再考虑前两位,使用掩码处理,每次将掩码所有的位使用 $and$ 置为 $0$ 。每次增加一位掩码,如果增加这一位掩码之后不能满足 $k$ 次操作之内,那么这一位不能被处理为 $0$ 了,在答案里面必须是 $1$ 。每次对 $nums[i] \& mask$ 取出需要考虑的位,然后进行与运算,如果不为 $0$ 就需要一次操作。
试填法,每次都尝试在这一位上填 $0$ ,判断可以不可以,不可以的话只能填 $1$ 。关键是使用掩码应对。
代码:
1 | auto optimize_cpp_stdio = []() |