1. 程式人生 > >合唱團 N個學生中選K個,相鄰兩個的位置編號不超過D,使得K個學生乘積最大

合唱團 N個學生中選K個,相鄰兩個的位置編號不超過D,使得K個學生乘積最大

網易2016內推筆試題:

有 n 個學生站成一排,每個學生有一個能力值,從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,返回最大的乘積。 每個輸入包含 1 個測試用例。每個測試資料的第一行包含一個整數 n (1 <= n <= 50),表示學生的個數,接下來的一行,包含 n 個整數,按順序表示每個學生的能力值 ai(-50 <= ai <= 50)。接下來的一行包含兩個整數,k 和 d (1 <= k <= 10, 1 <= d <= 50)。 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<set>
#include<queue>
using namespace std;
inline long long max(long long a, long long b){
	return (a > b) ? a : b;
}
inline long long min(long long a, long long b){
	return (a > b) ? b : a;
}

int main(int argc, char * argv[])
{
	int n, *a, k, d; // 選k個學生,位置編號不超過d
	// 尤其注意, dp_max[i][k] 表示在前 i 個數中選 k 個數,使得乘積最大, 且第 i 個數必選!!!!!!
	// 同理,dp_max[i][k] 表示在前 i 個數中選 k 個數,使得乘積最小, 且第 i 個數必選!!!!!!
	long long dp_max[52][12], dp_min[52][12];
	while (~scanf("%d", &n))
	{
		/*********** Input ****************/
		a = new int[n + 1];
		memset(a, 0, sizeof(int)*(n + 1));
		for (int i = 0; i < 52;i++)
		for (int j = 0; j < 12; j++)
		{
			dp_max[i][j] = 1;
			dp_min[i][j] = 1;
		}
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		cin >> k >> d;

		/*********** Algorithm ****************/
		// dynamic programing
		// initial
		dp_max[1][1] = dp_min[1][1] = a[1];
		for (int i = 1; i <= n; i++)
		for (int j = 1; j <= k; j++){
			// 
			for (int s = 1; s <= d; s++){
				if (i - s >= 1){
					dp_max[i][j] = max(dp_max[i][j], dp_max[i - s][j - 1] * a[i]);
					dp_max[i][j] = max(dp_max[i][j], dp_min[i - s][j - 1] * a[i]);
					dp_min[i][j] = min(dp_min[i][j], dp_min[i - s][j - 1] * a[i]);
					dp_min[i][j] = min(dp_min[i][j], dp_max[i - s][j - 1] * a[i]);
				}
			}
		}

		/*********** Output ****************/
		long long ans = 0;
		for (int i = 1; i <= n; i++)
			ans = max(ans, dp_max[i][k]);
		printf("%lld\n", ans);
	}

	return 0;
}