校招編程——合唱團
題目鏈接:合唱團
題目描述
- 有 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
時間限制:1000 ms,空間限制:32768 K
思路分析
- 動態規劃,假設已經選好了 index 個學生,那麼下一個學生選還是不選取決於與他相乘產生的價值是否大於當前已存在的最大價值,對於第 i 個學生,他前面的第 j 個學生與他價值之積就是產生狀態變化的原因,得到狀態轉移方程:\(value[index][i] = max(value[inex][i],value[index-1][j]*data[i])\)
- 由於題目中輸入數據存在負值,因此需要再開一個數組計算負值,並且在狀態方程中加入負數之積(偶數個相乘爲正數)的判斷
代碼
#include <iostream> #include <cstdio> using namespace std; typedef long long int ll; int n,k,d; ll ans; ll data[55],a[11][55],b[11][55]; int main() { int i,j; scanf("%d",&n); for(i = 1; i <= n; i++) scanf("%lld",&data[i]); scanf("%d%d",&k,&d); for(i = 0; i <= k; i++) for(j = 0; j <= n; j++,a[i][j] = b[i][j] = 0); for(i = 1,ans = 0; i <= n; i++) { a[1][i] = b[1][i] = data[i]; for(int index = 2; index <= k; index++) { for(j = i-1; j > 0 && i-j <= d; j--) { a[index][i] = max(a[index][i],max(a[index-1][j]*data[i],b[index-1][j]*data[i])); b[index][i] = min(b[index][i],min(a[index-1][j]*data[i],b[index-1][j]*data[i])); } } ans = max(ans,a[k][i]); } printf("%lld\n",ans); return 0; }