
2026-05-19:增加操作后最大按位与的结果。用go语言,已知一个整数数组 nums,以及两个整数 k 和 m。你可以进行至多 k 次操作:每次操作你可以选定数组中的某个位置 i,把 nums[i] 的值增加 1。
在最多做完这 k 次操作之后,从数组里任意挑选出 m 个元素组成一个子集(子集大小固定为 m),对这 m 个元素做按位与运算。你的目标是:让这个按位与的结果尽可能大。问最大的可能值是多少。
1 <= n == nums.length <= 50000。
1 <= nums[i] <= 1000000000。
1 <= k <= 1000000000。
1 <= m <= n。
输入: nums = [3,1,2], k = 8, m = 2。
输出: 6。
解释:
我们需要一个大小为 m = 2 的子集。选择下标 [0, 2]。
使用 3 次操作将 nums[0] = 3 增加到 6,并使用 4 次操作将 nums[2] = 2 增加到 6。
总共使用的操作次数为 7,不大于 k = 8。
这两个选定的值变为 [6, 6],它们的按位与结果是 6,这是可能的最大值。
题目来自力扣3806。
[1,2,3]二进制位数:理论最大值 7 是 3 位二进制(111),我们从**最高位(第2位)→ 最低位(第0位)**依次尝试:
初始答案 ans = 0(二进制 000),目标是尽可能把每一位变成 1。
0 | 4 = 4(二进制 100)[1,2,3]6(二进制 110)[3,4,5]7(二进制 111)[4,5,6]所有位尝试完毕,最终最大按位与结果为 6,和题目示例完全一致。 (操作方案:把3→6(3次)、2→6(4次),总7次≤8,两个数按位与=6)
O(W × n log n)
O(n)
ops,用于存储每个数的操作次数.
package main
import (
"fmt"
"math/bits"
"slices"
)
func maximumAND(nums []int, k, m int) (ans int) {
slices.Sort(nums)
n := len(nums)
maxAns := nums[n-1] + k/m
if nums[n-m] == nums[n-1] { // 最大的 m 个数都相等
return maxAns
}
ops := make([]int, n) // 每个数的操作次数
maxWidth := bits.Len(uint(maxAns))
for bit := maxWidth - 1; bit >= 0; bit-- {
target := ans | 1<<bit // 注意 target 要带着 ans 已经填好的 1
for i, x := range nums {
j := bits.Len(uint(target &^ x))
// j-1 是从高到低第一个 target 是 1 且 x 是 0 的比特位
// target = 10110
// x = 11010
// ^
// j-1
// x 二进制中的高于 j-1 的位不变,其余位增大到和 target 一样
// 上面的例子要把 010 变成 110
mask := 1<<j - 1
ops[i] = target&mask - x&mask
}
// 贪心,取前 m 小的操作次数
slices.Sort(ops)
sum := 0
for _, x := range ops[:m] {
sum += x
}
if sum <= k {
ans = target // 答案的 bit 位可以填 1
}
}
return
}
func main() {
nums := []int{3, 1, 2}
k := 8
m := 2
result := maximumAND(nums, k, m)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def maximumAND(nums, k, m):
nums.sort()
n = len(nums)
maxAns = nums[n-1] + k // m
# 最大的 m 个数都相等
if nums[n-m] == nums[n-1]:
return maxAns
ans = 0
ops = [0] * n # 每个数的操作次数
maxWidth = maxAns.bit_length()
for bit in range(maxWidth - 1, -1, -1):
target = ans | (1 << bit) # 注意 target 要带着 ans 已经填好的 1
for i, x in enumerate(nums):
# j 是从高到低第一个 target 是 1 且 x 是 0 的比特位
# 计算 target &^ x 的最高位位置
diff = target & ~x
if diff == 0:
j = 0
else:
j = diff.bit_length()
# x 二进制中的高于 j-1 的位不变,其余位增大到和 target 一样
mask = (1 << j) - 1
ops[i] = (target & mask) - (x & mask)
# 贪心,取前 m 小的操作次数
ops.sort()
total_sum = sum(ops[:m])
if total_sum <= k:
ans = target # 答案的 bit 位可以填 1
return ans
if __name__ == "__main__":
nums = [3, 1, 2]
k = 8
m = 2
result = maximumAND(nums, k, m)
print(result)
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <bitset>
using namespace std;
int maximumAND(vector<int>& nums, int k, int m) {
sort(nums.begin(), nums.end());
int n = nums.size();
int maxAns = nums[n - 1] + k / m;
// 最大的 m 个数都相等
if (nums[n - m] == nums[n - 1]) {
return maxAns;
}
int ans = 0;
vector<int> ops(n, 0); // 每个数的操作次数
int maxWidth = 32 - __builtin_clz(maxAns); // 计算二进制位数
for (int bit = maxWidth - 1; bit >= 0; bit--) {
int target = ans | (1 << bit); // 注意 target 要带着 ans 已经填好的 1
for (int i = 0; i < n; i++) {
int x = nums[i];
// 计算 target & ^x 的最高位位置
int diff = target & ~x;
int j = 0;
if (diff != 0) {
j = 32 - __builtin_clz(diff); // 计算 diff 的二进制位数
}
// j-1 是从高到低第一个 target 是 1 且 x 是 0 的比特位
// target = 10110
// x = 11010
// ^
// j-1
// x 二进制中的高于 j-1 的位不变,其余位增大到和 target 一样
// 上面的例子要把 010 变成 110
int mask = (1 << j) - 1;
ops[i] = (target & mask) - (x & mask);
}
// 贪心,取前 m 小的操作次数
sort(ops.begin(), ops.end());
int sum = 0;
for (int i = 0; i < m; i++) {
sum += ops[i];
}
if (sum <= k) {
ans = target; // 答案的 bit 位可以填 1
}
}
return ans;
}
int main() {
vector<int> nums = {3, 1, 2};
int k = 8;
int m = 2;
int result = maximumAND(nums, k, m);
cout << result << endl;
return0;
}
