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