✨题目链接:
✨题目描述
有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
✨输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
✨输出描述:
输出一行表示最大的乘积。
✨示例1
📍输入
3 7 4 7 2 50
📍输出
49
📍说明
输出一行表示最大的乘积。
✨解题思路
- 考虑以第i(i < n)个元素结尾作为选择的第k(k < K)个值
- 以前d个元素中最大的k-1个元素的乘积来更新当前元素的最大乘积
- 由于(-50 <= ai <= 50),存在负数,因此当第i个值为负数时,考虑前d个元素的最小值作为更新依据 因此状态转移方程为:
-
dpMAX[i][k]=max(dpMAX[i][k],max(dpMAX[j][k−1]∗arr[i],dpMIN[j][k−1]∗arr[i]))
dpMIN[i][k]=min(dpMIN[i][k],min(dpMAX[j][k−1]∗arr[i],dpMIN[j][k−1]∗arr[i]))
最终答案为max(dpMAX[i][K],0<=i<n)
✨代码
#include <iostream>
#include <limits.h>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = LLONG_MAX;
const int MINF = LLONG_MIN;
void solve(int n, int K, int d, vector<int>& arr){
vector<vector<ll>> dpMAX(n,vector<ll>(K+1,0)); // 最大值
vector<vector<ll>> dpMIN(n,vector<ll>(K+1,0)); // 最小值,由于存在负数,否则直接计算最大值即可
for(int i = 0; i < n; ++i){ // 初始化k=1时,以当前元素结尾的最大最小值
dpMAX[i][1] = arr[i];
dpMIN[i][1] = arr[i];
}
ll ans = MINF;
for(int i = 0; i < n; ++i){
for(int k = 2; k <= min(i+1,K); ++k){
for(int j = max(0, i-d); j < i; ++j){ // 再坐标差值<=d的范围内更新
dpMAX[i][k] = max( // 更新最大值
dpMAX[i][k], max(dpMAX[j][k-1]*arr[i], dpMIN[j][k-1]*arr[i])
);
dpMIN[i][k] = min( // 更新最小值
dpMIN[i][k], min(dpMAX[j][k-1]*arr[i], dpMIN[j][k-1]*arr[i])
);
}
}
ans = max(ans, dpMAX[i][K]); // 更新结果
}
cout<<ans<<endl;
return;
}
int main(){
int n,k,d;
cin>>n;
vector<int> arr(n);
for(int i = 0; i < n; ++i){
cin>>arr[i];
}
cin>>k>>d;
solve(n,k,d,arr);
return 0;
}
※ 如果文章对你有帮助的话,可以点赞收藏!!谢谢支持