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

 

转载于:https://www.cnblogs.com/yearning/p/11397116.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值