题意:有n个数和m个运算符,按顺序选m个数进行运算,初值为k,问最后能得到的最大值是多少。
思路:
dp[i][j]表示选到了第i个数时用了j个运算符,观察发现,一个数只能由他前一个状态的最大值或最小值转移过来(因为乘上一个负数会使最小的数变最大),所以我们同时维护最大最小。
转移方程:dp[i][j]=max(dp[i−1][j−1]∘now[i],dp[i−1][j])(i<j)
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=1e3+5;
ll dpmax[maxn][10],dpmin[maxn][10];
ll room[maxn];
int main()
{
int t;
cin>>t;
while(t--)
{
ll n,m,k;
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&room[i]);
char op[10];
scanf("%s",op+1);
memset(dpmax,0,sizeof dpmax);
memset(dpmin,0,sizeof dpmin);
dpmax[0][0]=k;
dpmin[0][0]=k;
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
{
if(j==0)
dpmax[i][j]=k,dpmin[i][j]=k;
else{
ll temp=dpmax[i-1][j-1],temp2=dpmin[i-1][j-1];
ll maxx,minn;
if(op[j]=='+')
{
maxx=max(temp+room[i],temp2+room[i]);
minn=min(temp+room[i],temp2+room[i]);
}
else if(op[j]=='-')
{
maxx=max(temp-room[i],temp2-room[i]);
minn=min(temp-room[i],temp2-room[i]);
}
else if(op[j]=='/')
{
maxx=max(temp/room[i],temp2/room[i]);
minn=min(temp/room[i],temp2/room[i]);
}
else{
maxx=max(temp*room[i],temp2*room[i]);
minn=min(temp*room[i],temp2*room[i]);
}
dpmax[i][j]=max(maxx,dpmax[i-1][j]);
dpmin[i][j]=min(minn,dpmin[i-1][j]);
if(i==j)
{
dpmax[i][j]=maxx;
dpmin[i][j]=minn;
}
}
}
printf("%lld\n",dpmax[n][m]);
}
return 0;
}