题意:
有一个算术表达式 x1 Δ x2 Δ x3 Δ ,..., Δ xn, x1,x2,x3,...,xn 是1到 9的数字, Δ是'+'或者'*'。
现在要求你在这个表达式中加一对括号,使得这个式子的值最大。
样例解释:3 + 5 * (7 + 8) * 4 = 303。
题解:
①区间DP预处理出任意i~j之间的表达式的值
②贪心枚举括号的左右端点
③此题AC
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=5000+10; typedef long long LL; char s[maxn]; int n,Pre[maxn],Next[maxn]; LL f[maxn][maxn]; void Prework(); void Tanxin(); signed main(){ scanf("%s",s+1); n=strlen(s+1); Prework(); Tanxin(); return 0; } void Prework(){ Pre[0]=0; for(int i=1;i<=n;i++)//Pre[i]记录i之前离i最近的'+'的位置 if(s[i]=='+')Pre[i]=i; else Pre[i]=Pre[i-1]; Next[n+1]=n+1; for(int i=n;i>=1;i--)//Next[i]记录i之后离i最近的'+'的位置 if(s[i]=='+')Next[i]=i; else Next[i]=Next[i+1]; for(int i=1;i<=n;i+=2)f[i][i]=s[i]-'0'; for(int len=3;len<=n;len+=2)//f[i][j]表示将i~j用括号括起来,i~j的值为多少 for(int i=1,j;(j=i+len-1)<=n;i+=2) if(Pre[j]<i)f[i][j]=f[i][j-2]*(s[j]-'0'); //Pre[j]<i,说明[i,j-2]和j之间是'*' else f[i][j]=f[i][Pre[j]-1]+f[Pre[j]+1][j]; //否则说明[i,j-2]和j之间是'+' } void Tanxin(){ LL ans=f[1][n]; for(int i=1;i<=n;i+=2){ for(int j=i+2;j<=n;j+=2){ if(s[i-1]!='*' && s[j+1]!='*')continue; //枚举()的左右边界[i,j] //只有将两个'*'之间的式子扩起来才能获得更优答案 LL Add=0;//Add记录和[i,j]相加的值 if(Pre[i]>0)Add+=f[1][Pre[i]-1]; //只有i左边还有'+',i左边才能有不和[i,j]有关的值 if(Next[j]<n+1)Add+=f[Next[j]+1][n]; //j的右边同理 LL Multi=f[i][j];//Multi记录和[i,j]相乘之后的值 if(Pre[i]+1<=i-2)Multi*=f[Pre[i]+1][i-2]; //i左边第一个'*'向右到i-2的所有式子都是与[i,j]相乘 if(Next[j]-1>=j+2)Multi*=f[j+2][Next[j]-1]; //j右边同理 ans=max(ans,Add+Multi); } } printf("%lld\n",ans ); }