题目描述
在一个长度为 n 的数组 arr 中,你需要进行一系列操作。每个操作有两种类型:
- 加法操作:选择一个索引 i,将 arr[i] 增加 val。
- 减法操作:选择一个索引 i,将 arr[i] 减少 val。
目标是通过不超过 k 次操作,使得数组 arr 中所有元素的最大值尽可能小。返回这个最小的最大值。
输入
- 第一行包含三个整数 n, k, val,分别表示数组的长度、最大操作次数和每次操作的增减值。
- 第二行包含 n 个整数,表示数组 arr。
输出
- 输出一个整数,表示经过最多 k 次操作后,数组 arr 中所有元素的最大值的最小可能值。
示例
输入:
5 4 2
1 3 5 7 9
输出:
5
思路
- 二分搜索:我们可以观察到,数组中的最大值的最小可能值必然在某个范围内,即数组中的最小值和最大值之间。因此,我们可以使用二分搜索来找到这个最小的最大值。
- 校验可行性:对于每一个二分搜索的中间值 mid,我们需要检查是否可以通过不超过 k 次操作使得数组中的所有元素都不超过 mid。
- 计算操作次数:对于每个元素 arr[i],如果需要将其调整到不超过 mid,计算需要的操作次数,并累加这些次数。如果总操作次数不超过 k,则当前 mid 是一个可能的解,继续在左侧搜索更小的值;否则,继续在右侧搜索更大的值。
Java 编码解析
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int val = sc.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
sc.close();
int left = Integer.MAX_VALUE;
int right = Integer.MIN_VALUE;
for (int num : arr) {
left = Math.min(left, num);
right = Math.max(right, num);
}
while (left < right) {
int mid = left + (right - left) / 2;
if (canAdjust(arr, n, k, val, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
System.out.println(left);
}
private static boolean canAdjust(int[] arr, int n, int k, int val, int target) {
int operations = 0;
for (int num : arr) {
int diff = Math.abs(num - target);
operations += diff / val; // Integer division to get number of val adjustments
if (diff % val != 0) {
operations++; // If there's a remainder, we need one more operation
}
if (operations > k) {
return false;
}
}
return true;
}
}
C++ 编码解析
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;
bool canAdjust(const vector<int>& arr, int n, int k, int val, int target) {
int operations = 0;
for (int num : arr) {
int diff = abs(num - target);
operations += diff / val; // Integer division to get number of val adjustments
if (diff % val != 0) {
operations++; // If there's a remainder, we need one more operation
}
if (operations > k) {
return false;
}
}
return true;
}
int main() {
int n, k, val;
cin >> n >> k >> val;
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
cin >> arr[i];
}
int left = INT_MAX;
int right = INT_MIN;
for (int num : arr) {
left = min(left, num);
right = max(right, num);
}
while (left < right) {
int mid = left + (right - left) / 2;
if (canAdjust(arr, n, k, val, mid)) {
right = mid;
} else {
left = mid + 1;
}
}
cout << left << endl;
return 0;
}
Python 编码解析
def can_adjust(arr, k, val, target):
operations = 0
for num in arr:
diff = abs(num - target)
operations += diff // val # Integer division to get number of val adjustments
if diff % val != 0:
operations += 1 # If there's a remainder, we need one more operation
if operations > k:
return False
return True
def main():
import sys
input = sys.stdin.read
data = input().split()
n = int(data[0])
k = int(data[1])
val = int(data[2])
arr = list(map(int, data[3:3+n]))
left = min(arr)
right = max(arr)
while left < right:
mid = left + (right - left) // 2
if can_adjust(arr, k, val, mid):
right = mid
else:
left = mid + 1
print(left)
if __name__ == "__main__":
main()