题目链接
题目描述
小红有一个长度为 的数组。小红初始分数为
。小红每次选择两个整数,这两个数的差值不能超过
,小红获得这两个数的乘积的分数,被选择过的数不能再选择。问小红最多能获得多少分数?
输入:
- 第一行输入两个整数
和
- 第二行输入
个整数
输出:
- 输出一个整数,表示小红能获得的最大分数
解题思路
这是一个贪心问题,可以通过以下步骤解决:
-
关键发现:
- 两个数的差值不能超过
- 每个数只能使用一次
- 需要使乘积和最大
- 两个数的差值不能超过
-
解题策略:
- 将数组排序
- 从大到小遍历数组
- 对每个数找到差值不超过
的最大数配对
- 使用标记数组避免重复使用
-
具体步骤:
- 对数组进行排序
- 从大到小遍历每个数
- 在未使用的数中找到差值不超过
的最大数
- 累加乘积到答案中
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
vector<int> a(n);
for(int i = 0; i < n; i++) {
cin >> a[i];
}
// 排序
sort(a.begin(), a.end());
vector<bool> used(n, false);
long long ans = 0;
// 从大到小遍历
for(int i = n-1; i >= 0; i--) {
if(used[i]) continue;
// 找到差值不超过k的最大未使用数
int maxj = -1;
for(int j = i-1; j >= 0; j--) {
if(!used[j] && a[i] - a[j] <= k) {
maxj = j;
break;
}
}
if(maxj != -1) {
ans += (long long)a[i] * a[maxj];
used[i] = used[maxj] = true;
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] a = new int[n];
for(int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
// 排序
Arrays.sort(a);
boolean[] used = new boolean[n];
long ans = 0;
// 从大到小遍历
for(int i = n-1; i >= 0; i--) {
if(used[i]) continue;
// 找到差值不超过k的最大未使用数
int maxj = -1;
for(int j = i-1; j >= 0; j--) {
if(!used[j] && a[i] - a[j] <= k) {
maxj = j;
break;
}
}
if(maxj != -1) {
ans += (long)a[i] * a[maxj];
used[i] = used[maxj] = true;
}
}
System.out.println(ans);
}
}
n, k = map(int, input().split())
a = list(map(int, input().split()))
# 排序
a.sort()
used = [False] * n
ans = 0
# 从大到小遍历
for i in range(n-1, -1, -1):
if used[i]:
continue
# 找到差值不超过k的最大未使用数
maxj = -1
for j in range(i-1, -1, -1):
if not used[j] and a[i] - a[j] <= k:
maxj = j
break
if maxj != -1:
ans += a[i] * a[maxj]
used[i] = used[maxj] = True
print(ans)
算法及复杂度
- 算法:贪心
- 时间复杂度:
- 排序的复杂度
- 空间复杂度:
- 需要存储标记数组
注意:
- 需要使用
long long/long
类型避免乘法溢出 - 从大到小遍历可以保证获得最大乘积
- 使用标记数组避免重复使用数字
- 注意差值不超过
的判断条件