ACM-ICPC 2018焦作赛区网络预赛 B.Mathmatical Curse(dp基础)

题目

有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;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89323548