题意
有n个数字,m个运算符合(包括+、-、*、/)。给定初值k,求将所有符号用完,可得到的最大值。
题解
本题形式上是一个简单的线性dp,但是由于题目的特殊性,需要同时维护最大值和最小值。而这一点是我之前没有考虑过的。
之前,自己对dp的理解就是,将dp定义为题目要求的答案,之后按照顺序转移状态即可。但是,我忽略了他们之间一个共同点:每一步转移都只会从之前状态的一个值转移过来,而且在我之前做的题中,对dp定义和题目答案的要求是统一的。现在看来这可能只是一个巧合。题目要求某一最大值,而dp完全可能维护最小值。
做个猜想:动态规划维护的值的个数并不一定是一个。由于题目的特性,状态可能会从多个极值中转移过来。有多少种可能就需要维护多少个极值
AC代码
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
const int maxn = 1001;
const ll INF = 1e18+1;
ll dp1[maxn][10],dp2[maxn][10];
char f[10];
int a[maxn];
int n,m,k;
ll w(ll x, char fj, ll ai){
if(fj=='+') return x+ai;
if(fj=='-') return x-ai;
if(fj=='*') return x*ai;
if(fj=='/') return x/ai;
return -1;
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i<=n; i++){
scanf("%d", a+i);
}
getchar();
for(int i = 1; i<=m; i++){
scanf("%c", f+i);
}
for(int i = 1; i <= n; i++){
dp1[i][0] = dp2[i][0] = k;
}
dp1[1][1] = dp2[1][1] = w(k, f[1], a[1]);
for(int i = 2; i <= n; i++){
for(int j = 1; j <= min(i,m); j++){
dp1[i][j] = max(w(dp1[i-1][j-1], f[j], a[i]), w(dp2[i-1][j-1], f[j], a[i]));
dp2[i][j] = min(w(dp1[i-1][j-1], f[j], a[i]), w(dp2[i-1][j-1], f[j], a[i]));
if(i > j){
dp1[i][j] = max(dp1[i][j], dp1[i-1][j]);
dp2[i][j] = min(dp2[i][j], dp2[i-1][j]);
}
}
}
printf("%lld\n", dp1[n][m]);
}
return 0;
}