網易內推題,合唱團,C++實現
阿新 • • 發佈:2019-02-12
有 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
#include <iostream> #include <vector> #include <algorithm> #include <climits> using namespace std; void Hechang() { int n, K, d; cin >> n; vector<int> nums(n); for (int i = 0; i < n; i++) cin >> nums[i]; cin >> K >> d; //dp_max[k][i]表示當選中了k個學生,並且以第i個學生為結尾,所產生的最大乘積. vector<vector<long long>> dp_max(K + 1, vector<long long>(n + 1, 0)); vector<vector<long long>> dp_min(K + 1, vector<long long>(n + 1, 0)); long long res = LLONG_MIN; for (int i = 0; i < n;i++) { //狀態開頭的初始情況,如果只選了一個學生,那麼這個人就是第i個學生。 dp_max[1][i] = dp_min[1][i] = nums[i]; //從k=2開始迴圈,進入狀態解釋方程。先解決子問題,也就是人少的時候的dp_max,dp_min,然後遞推。 for (int k = 2; k <= K;k++) { for (int j = i - 1; j > -1 && i - j <= d;j--) /*j初始是i左邊一位,也即末尾左邊一位的數。 但它或許與再之前乘積最大數的乘積不是最大,因此需要j--找再之前最大的數。 全部迴圈完畢以後,找到乘積最大的末尾位置,作為dp_max[k-1][j]提供給dp_max[k][i]。 即每個i都有一個dp_max[K][i],但當我們計算dp_max[K+1][i+1]時,需要找到dp_max[K][i]最大的那個i。 相鄰的人之間差距不能超過D,然後反向推導。含0的陣列都空出來了所以j>0。*/ { dp_max[k][i] = max(dp_max[k][i], max(dp_max[k - 1][j] * nums[i], dp_min[k - 1][j] * nums[i])); dp_min[k][i] = min(dp_min[k][i], min(dp_min[k - 1][j] * nums[i], dp_max[k - 1][j] * nums[i])); /*因為上一個為最大負值也可能乘以一個負數變為正數。 同時由於k個人變成了k+1個人,因此原來結尾是i,現在結尾變成了i+1。 先由k=2開始實現迴圈,找出dp_max[2][i],dp_min[2][i],由此再通過遞推式找出dp_max[3][i],dp_min[3][i]直至dp_max[K][i]。 注意i也是在迴圈,因為結尾不可能永遠是一個值,因此i也要不斷變化。*/ } } res = max(res, dp_max[K][i]); } cout << res; } int main() { Hechang(); system("pause"); return 0; }