luogu传送门

 

题解

一道经典的区间DP,既又环形结构,又需要思考怎样维护“最优子结构”的性质

首先我们不难想到用dp[l,r]表示第l个节点和第r个节点合并后最大顶点上的最大值

如果只是有加法运算,其实就与合并石子无异

但问题来了——有乘法

所以如果我们只维护最大值,显然不对

例如:5*5<-9*-9

这启示我们同时维护一个最小值

我们简单来说:

乘法

最大值 维护: 最大乘最大 最小乘最小

最小值 维护: 最大乘最大  最小乘最小  前大乘后小  前小乘后大

加法 

最大值 维护: 最大加最大 

最小值 维护: 最小加最小 

这样下来这个题就不难了qwq

CODE

#include<cstdio>
#include<algorithm>
#define mxx 0x7fffffff
using namespace std;
int n,ans=-mxx,a[150],mx[150][150],mn[150][150];
char c[150];
int main()
{
    register int i,j,k,len;
    scanf("%d\n",&n);
    for(i=1;i<=n;++i) scanf("%c %d",&c[i],&a[i]),getchar(),a[n+i]=a[i],c[n+i]=c[i];
    for(i=1;i<=(n<<1);++i) for(j=1;j<=(n<<1);++j) mx[i][j]=-mxx,mn[i][j]=mxx;
    for(i=1;i<=(n<<1);++i) mx[i][i]=mn[i][i]=a[i];
    for(len=1;len<=n;++len)
      for(i=1,j=len;j<=(n<<1);++i,++j)
          for(k=i;k<j;++k)
          {
            if(c[k+1]=='x')
            {
                mx[i][j] = max(mx[i][j],max(mx[i][k]*mx[k+1][j],mn[i][k]*mn[k+1][j])); 
                mn[i][j] = min(mn[i][j],min(mx[i][k]*mx[k+1][j],min(mn[i][k]*mn[k+1][j],min(mn[i][k]*mx[k+1][j],mx[i][k]*mn[k+1][j])))); 
            }
            else if(c[k+1]=='t')
            {
                mx[i][j] = max(mx[i][j],mx[i][k]+mx[k+1][j]);
                mn[i][j] = min(mn[i][j],mn[i][k]+mn[k+1][j]);
            }
        }    
    for(i=1;i<=n;++i) ans=max(ans,mx[i][i+n-1]);    
    printf("%d\n",ans);
    for(i=1;i<=n;++i) if(ans==mx[i][i+n-1]) printf("%d ",i);
    return 0;
}