[IOI1998]Polygon
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; }