• 【IOI1998】Polygon


    一道区间dp题,不少细节。

    一开始我想定义f[i][j]表示区间[i,j]通过某种合并之后的最大值,之后这道题就等同于“NOI1995石子合并”。

    但是转念一想,这道题有加法和乘法两种运算,如果单看加法,以上思路正确。但是因为乘法的存在,两个较小的数(负数)相乘或许会大于两个最大数相乘,因此以上思路在这里出现了错误。

    因此,我们定义maxx[i][j],minn[i][j]分别表示区间[i,j]通过某种合并之后的最大值、最小值。

    1、如果当前枚举决策为k,而且运算符为加号,则有

     maxx[i][j]=max(maxx[i][k-1]+maxx[k][j]);

     minn[i][j]=min(minn[i][k-1]+minn[k][j]);

     如果运算符为乘号,则有

     maxx[i][j]=max(maxx[i][k-1]*maxx[k][j]);
     maxx[i][j]=max(minn[i][k-1]*minn[k][j]);
     minn[i][j]=min(maxx[i][k-1]*maxx[k][j]);
     minn[i][j]=min(minn[i][k-1]*minn[k][j]);
     minn[i][j]=min(maxx[i][k-1]*minn[k][j]);
     minn[i][j]=min(minn[i][k-1]*maxx[k][j]);

    因此正确的算法就得出来了,我们枚举起始的位置开始计算即可,时间复杂度为O(n4).

    在这里我们将这个环拆开并复制一倍,然后在这个两倍长的链上做一次dp,最后枚举起点选出答案即可,时间复杂度为O(n3).

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 int n,maxx[60<<1][60<<1],minn[60<<1][60<<1],a[60<<1];
     6 char op[60<<1];
     7 int main() {
     8     cin>>n;
     9     memset(minn,0x3f,sizeof(minn));
    10     memset(maxx,-0x3f,sizeof(maxx));
    11     for(int i=1;i<=n;i++) {
    12         char x;
    13         int y;
    14         cin>>x>>y;
    15         a[i]=a[i+n]=y;
    16         op[i]=op[i+n]=x;
    17     }
    18     for(int i=1;i<=n<<1;i++) 
    19         maxx[i][i]=minn[i][i]=a[i];
    20     for(int i=2;i<=n;i++) {
    21         for(int l=1;l+i-1<=2*n;l++) {
    22             for(int k=l+1;k<=l+i-1;k++) {
    23                 if(op[k]=='t') {
    24                     maxx[l][l+i-1]=max(maxx[l][l+i-1],maxx[l][k-1]+maxx[k][l+i-1]);
    25                     minn[l][l+i-1]=min(minn[l][l+i-1],minn[l][k-1]+minn[k][l+i-1]);
    26                 }
    27                 else {
    28                     maxx[l][l+i-1]=max(maxx[l][l+i-1],maxx[l][k-1]*maxx[k][l+i-1]);
    29                     maxx[l][l+i-1]=max(maxx[l][l+i-1],minn[l][k-1]*minn[k][l+i-1]);
    30                     minn[l][l+i-1]=min(minn[l][l+i-1],maxx[l][k-1]*maxx[k][l+i-1]);
    31                     minn[l][l+i-1]=min(minn[l][l+i-1],minn[l][k-1]*minn[k][l+i-1]);
    32                     minn[l][l+i-1]=min(minn[l][l+i-1],maxx[l][k-1]*minn[k][l+i-1]);
    33                     minn[l][l+i-1]=min(minn[l][l+i-1],minn[l][k-1]*maxx[k][l+i-1]);
    34                 }
    35             }
    36         }
    37     }
    38     int ans=-0x7fffffff;
    39     for(int i=1;i<=n;i++)
    40         ans=max(ans,maxx[i][i+n-1]);
    41     cout<<ans<<endl;
    42     for(int i=1;i<=n;i++)
    43         if(ans==maxx[i][i+n-1]) cout<<i<<" ";
    44     return 0; 
    45 }
    AC Code
  • 相关阅读:
    PHP string
    MUI体验框架
    OPP面向对象的介绍及使用
    分享一个实用插件(页面滚动触发动画)以及其内部的所有动画属性值
    对于Bootstrap的介绍以及如何使用
    JS中的内置对象简介与简单的属性方法
    如何使用JS实现banner图滚动
    如何用JavaScript制作循环图形
    javascript高级程序设计阅读总结
    读心术小游戏
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10664527.html
Copyright © 2020-2023  润新知