zoukankan      html  css  js  c++  java
  • Luogu4342 [IOI1998]Polygon(区间DP)题解

    题意

    合并一堆数,每次合并相加或相乘(题目已给出),设计合并顺序使得最终答案最大

    其实就是一个区间DP

    (f_{i, j})为合并区间([i,j])的最大价值

    加法很好写:(f_{i, j} = max_{k geq i}^{k < j}{(f_{i, k} + f_{k + 1, j})})

    乘法也很好写:(f_{i, j} = max_{k geq i}^{k < j}{(f_{i, k} * f_{k + 1, j})})

    然而

    你会发现过不了样例……

    ??????

    仔细想一想,事实上,因为存在负数,所以对于乘法操作,最大值完全可能是由两个极小的负数相乘得到的。因此,我们还需要DP一个最小值。

    (g_{i, j})为合并区间([i,j])的最小价值

    那么乘法转移应该写成:

    f[i][j] = max(f[i][j], f[i][k] * f[k + 1][j]);
    f[i][j] = max(f[i][j], f[i][k] * g[k + 1][j]);
    f[i][j] = max(f[i][j], g[i][k] * f[k + 1][j]);
    f[i][j] = max(f[i][j], g[i][k] * g[k + 1][j]);
    

    (g)的转移也是同理的。

    完整代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 110;
    int n,f[maxn][maxn],opt[maxn],a[maxn],g[maxn][maxn];
    char c[5];
    
    int main(){
        scanf("%d", &n);
        for(int i = 1; i <= n; ++ i){
            scanf("%s%d", c, a + i);
            if(c[0] == 'x') opt[i] = opt[i + n] = 2;
            else opt[i] = opt[i + n] = 1;
        }
        memset(f,-0x3f,sizeof(f));
        memset(g,0x3f,sizeof(g));
        for(int i = 1; i <= n; ++ i) a[i + n] = a[i];
        n *= 2;
        for(int i = 1; i <= n; ++ i) f[i][i] = g[i][i] = a[i];
        for(int l = 1; l < n; ++ l)
            for(int i = 1, j = i + l; i < n && j <= n; ++ i, j = i + l)
                for(int k = i; k < j; ++ k){
                    if(opt[k + 1] == 1){
                        f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j]);
                        g[i][j] = min(g[i][j], g[i][k] + g[k + 1][j]);
                    } 
                    else{
                        f[i][j] = max(f[i][j], f[i][k] * f[k + 1][j]);
                        f[i][j] = max(f[i][j], f[i][k] * g[k + 1][j]);
                        f[i][j] = max(f[i][j], g[i][k] * f[k + 1][j]);
                        f[i][j] = max(f[i][j], g[i][k] * g[k + 1][j]);
                        g[i][j] = min(g[i][j], g[i][k] * g[k + 1][j]);
                        g[i][j] = min(g[i][j], f[i][k] * g[k + 1][j]);
                        g[i][j] = min(g[i][j], g[i][k] * f[k + 1][j]);
                        g[i][j] = min(g[i][j], f[i][k] * f[k + 1][j]);
                    } 
                }
        int Ans = -0x3f3f3f3f;
        n /= 2;
        for(int i = 1; i <= n; ++ i) Ans = max(Ans, f[i][i + n - 1]);
        printf("%d
    ", Ans);
        for(int i = 1; i <= n; ++ i)
            if(f[i][i + n - 1] == Ans) printf("%d ", i); 
        return 0;
    }
    
  • 相关阅读:
    UITableView的一些事1
    Mac修改文件权限:You don’t have permission to save the file
    svn: is already a working copy for a different url 解决办法
    svn服务配置
    github push出错(1)You can't push to git:// Use https://
    判断系统版本
    浅谈 Qt 布局那些事
    Qt布局管理
    详解 QT 主要类 QWidget
    新手须知 QT类大全
  • 原文地址:https://www.cnblogs.com/whenc/p/13949538.html
Copyright © 2011-2022 走看看