题目
有n(n<=1e3)个数,第i个数为ai(-1e3<=ai<=1e3)
m(m<=5)个操作符,操作符必须顺序使用,不能更改n个数的顺序,
问最终能取得的最大值是多少
思路来源
https://blog.csdn.net/Tighway/article/details/82716717
https://blog.csdn.net/Lfhase/article/details/82718667
题解
dp[i][j]维护的是到第i个数,用了j个运算符的最值
此处dp[i][j][0]维护最大值,dp[i][j][1]维护最小值
注意到最大值是可以由最小值*负数转移过来,
同理最小值也可以由最大值*负数转移而来
所以转移的时候暴力转移四个递推式即可
好在有小于等于5个乘号,所以绝对值不会超过1e18,
初始化的值赋1e18以外的值即可
心得
开始WA了好几发,后来发现是忘了对dp[0][j][0]和dp[0][j][1]初始化了
减少出错的话,以后还是memset或单独赋值叭
这么写在一起太容易出错了,debug15min
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int T;
ll n,m,k;
ll a[1005],dp[1005][10][2];
char s[15];
ll cal(ll x,char op,ll y)
{
if(op=='+')return x+y;
if(op=='-')return x-y;
if(op=='*')return x*y;
if(op=='/')return x/y;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&k);
for(int i=0;i<=n;++i)
{
if(i)scanf("%lld",&a[i]);
dp[i][0][0]=dp[i][0][1]=k;
for(int j=1;j<=m;++j)
{
dp[i][j][0]=-1e18;//max
dp[i][j][1]=1e18;//min
}
}
scanf("%s",s+1);
for(ll i=1;i<=n;++i)
{
for(ll j=1;j<=m;++j)
{
if(j>i)break;
dp[i][j][0]=max(dp[i-1][j][0],cal(dp[i-1][j-1][0],s[j],a[i]));
dp[i][j][0]=max(dp[i][j][0],cal(dp[i-1][j-1][1],s[j],a[i]));
dp[i][j][1]=min(dp[i-1][j][1],cal(dp[i-1][j-1][0],s[j],a[i]));
dp[i][j][1]=min(dp[i][j][1],cal(dp[i-1][j-1][1],s[j],a[i]));
}
}
printf("%lld\n",dp[n][m][0]);
}
return 0;
}