网易编程题(合唱团)
有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
输出描述:
输出一行表示最大的乘积。
输入例子:
3
7 4 7
2 50
输出例子:
49
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
long long temp_k = -1e17;
vector< long long > students;
long long n;
cin >> n;
long long sum = n;
while (n--)
{
long long temp;
cin >> temp;
students.push_back(temp);
}
long long k, d;
cin >> k >> d;
struct min_max{
min_max() :min{ 0 }, max{ 0 }{};
long long min;
long long max;
};
//声明结构体,因为有正有负所以要保存最大值和最小值
//vector<vector< long long >> *res = new vector<vector< long long >>{ n, vector< long long >{d, 0} };
vector<vector<min_max>> *res =
new vector<vector< min_max>>(sum, vector<min_max>(k, min_max()));
for (long long i = 0; i <sum; ++i)
{
(*res)[i][0].max = (*res)[i][0].min = students[i];
}
//以i结尾的至多包含k个数字的成绩的最大值和最小值;
for (long long i = 1; i <sum; ++i)
{
for (long long j = 1; j <= i&&j < k; ++j)
{
long long temp_min = -1e17;
long long temp_max = 1e17;
for (long long w = 1; w<i + 1 && w <= d; ++w){
if (temp_min<max(students[i] * (*res)[i - w][j - 1].min,
students[i] * (*res)[i - w][j - 1].max))
temp_min = max(students[i] * (*res)[i - w][j - 1].min,
students[i] * (*res)[i - w][j - 1].max);
if (temp_max>min(students[i] * (*res)[i - w][j - 1].min,
students[i] * (*res)[i - w][j - 1].max))
temp_max = min(students[i] * (*res)[i - w][j - 1].min,
students[i] * (*res)[i - w][j - 1].max);
}
(*res)[i][j].max = temp_min;
(*res)[i][j].min = temp_max;
}
}
for (auto c : (*res))
{
if (c[k - 1].max>temp_k)
temp_k = c[k - 1].max;
}
cout << temp_k << endl;
delete res;
return 0;
}