問題描述:
有 n 個學生站成一排,每個學生有一個能力值,牛牛想從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,你能返回最大的乘積嗎?
dp[i][j]表示 依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最大爲多少 應該是i>=j
dp[i][j] = arr[i] * max(dp[i-1][j-di]);
邊界條件 dp[0][j]=1;
但是因爲每個學生的能力有正有負,所以如果arr[i]爲負值,那麼dp[i][j] = arr[i] * min(dp[i-1][j-di]);
我們可以
用dp1[i][j]表示依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最大爲多少
用dp2[i][j]表示依次選好第i個學生時 他在隊伍裏排第j名能力值乘積最小爲多少
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long int
const ll maxn = 55;
ll arr[maxn];
ll dp1[maxn][maxn]; //存最大值
ll dp2[maxn][maxn]; //存最小值
int main()
{
ll n; //n個學生
while(cin>>n)
{
for(ll i=1;i<=n;++i)
{
cin>>arr[i]; //每個學生的能力值有正有負
}
ll k,d; //k個學生,編號差值不超過d
cin>>k>>d;
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
for(ll i=0;i<=n;++i)
{
dp1[0][i]=1;
dp2[0][i]=1;
}
for(ll i=1;i<=k;++i)
{
for(ll j=1;j<=n;++j)
{
if(i>j) continue; //選好了I個人,他不可能在原來的隊伍
ll num1 = -1<<30;
ll num2 = 1<<30;
for(int m=1;m<=d;++m)
{
if(j-m<0) break;
num1=max(num1,dp1[i-1][j-m]);
num2=min(num2,dp2[i-1][j-m]);
}
dp1[i][j] =max(num2 * arr[j], num1 * arr[j]);
dp2[i][j] =min(num2 * arr[j], num1 * arr[j]);
}
}
ll ans = -1<<30;
// for(int i=0;i<=k;++i)
// {
// for(int j=1;j<=n;++j)
// {
// cout<<dp1[i][j]<<" ";
// }
// cout<<endl;
// }
for(ll i=k;i<=n;++i)
{
ans = max(ans,dp1[k][i]);
}
cout<<ans<<endl;
}
return 0;
}