题目链接
题目描述
小红有一个长度为 的数组
。她可以多次执行如下操作:
- 选择数组中两个之前未被选择过的整数
和
,需满足
。
- 获得
的分数。
问小红最多能获得多少分数?
解题思路
这是一个可以通过动态规划解决的最优配对问题。
1. 预处理
为了最大化乘积之和,我们应该优先考虑将数值相近且较大的数配对。这启发我们首先对数组进行排序。将数组 从小到大排序后,配对条件
(假设
) 就简化为
。
2. 动态规划
排序后,问题具有了最优子结构,适合使用动态规划求解。
-
状态定义:
我们定义
为:考虑排序后数组的前
个元素(即
)所能获得的最大分数。
-
状态转移方程:
在计算
时,我们主要关注第
个元素
的决策。它有两种可能:
-
不参与配对:如果
不与任何元素配对,那么它就被放弃了。此时,前
个元素能获得的最大分数就等于只考虑前
个元素时的最大分数。即
。
-
与
配对:如果我们将
与它紧邻的前一个元素
配对,这必须满足条件
。如果满足,我们会获得
的分数,并且这两个元素都不能再被使用。此时的总分数为这对元素的分数加上前
个元素能获得的最大分数,即
。
综合这两种情况,
的值应为两者的最大值。因此,转移方程为:
- 如果
且
,则
-
-
基础情况:
(没有元素,分数为0)
(只有一个元素,无法配对,分数为0)
-
最终答案:
最终结果为
。
注意:分数可能会很大,需要使用 64 位整型(long long
)来存储。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
long long k;
cin >> n >> k;
vector<long long> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
sort(a.begin(), a.end());
vector<long long> dp(n + 1, 0);
for (int i = 2; i <= n; ++i) {
dp[i] = dp[i-1]; // Case 1: a[i-1] is not paired
if (a[i-1] - a[i-2] <= k) {
dp[i] = max(dp[i], (i > 2 ? dp[i-2] : 0) + a[i-1] * a[i-2]);
}
}
cout << dp[n] << endl;
return 0;
}
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long k = sc.nextLong();
long[] a = new long[n];
for (int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
Arrays.sort(a);
long[] dp = new long[n + 1];
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1]; // Case 1: a[i-1] is not paired
if (a[i - 1] - a[i - 2] <= k) {
long pairScore = a[i - 1] * a[i - 2];
long previousScore = (i > 2) ? dp[i - 2] : 0;
dp[i] = Math.max(dp[i], previousScore + pairScore);
}
}
System.out.println(dp[n]);
}
}
import sys
def solve():
n, k = map(int, sys.stdin.readline().split())
a = list(map(int, sys.stdin.readline().split()))
a.sort()
dp = [0] * (n + 1)
for i in range(2, n + 1):
dp[i] = dp[i-1] # Case 1: a[i-1] is not paired
if a[i-1] - a[i-2] <= k:
pair_score = a[i-1] * a[i-2]
previous_score = dp[i-2] if i > 2 else 0
dp[i] = max(dp[i], previous_score + pair_score)
print(dp[n])
solve()
算法及复杂度
- 算法:动态规划
- 时间复杂度:
,瓶颈在于对数组的排序。DP 过程本身是线性的,为
。
- 空间复杂度:
,用于存储 DP 状态数组。