zoukankan      html  css  js  c++  java
  • 2018ACM-ICPC EC-Final 现场赛I题 Misunderstanding...Missing 倒着DP

    (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

    Catalog

    @

    Problem:

     很多acm群里有题面PDF了,我就不赘述了。简单说一下,你有n次操作,每次操作有3种选择,1.造成A+ai点伤害;2.永久给D增加bi;3.永久给A增加ci。(每次操作前执行:A+=D)。问最后最多造成多少伤害。

    Solution:

     这么明显的dp却没有想到,真实太菜了。当时想到要从后往前推,但就是卡着不知道怎么转移最优,如何平衡3种操作。赛后看到qls的状态定义,终于理解qls的意思了。菜是原罪啊。

    状态表示:
    (dp[i][j][k])表示从后开始执行到第(i)步,执行了(j)次操作1,选择操作1的下标和为(k)所造成的最高伤害。

    初始化:

    memset(dp, -1, sizeof(dp));//必须初始化为-1,因为你要确保状态的正确性,也就是j次操作1的下标和真的是k才行。
    dp[n][1][n] = cw[n].a;//因为最后一次肯定是要打伤害的
    

    状态转移方程:

    [dp[i][j][k] = max(dp[i+1][j][k]+max(c*j, b*(k-i*j)), dp[i+1][j-1][k-i]+a); ]


    - 第一部分是第$i$次选择操作2或3,第二部分是第$i$次选择操作1。 - 如果这一次选择操作3,显然后面的$j$次伤害需要增加$c*j$。 - 同理:选择操作2,后面每次操作需要增加$b*(x-i)$点伤害,$x$是选择操作1的编号,求个和之后就是$b*(k-i*j)$了。 - 到这里,这题就解决啦。

    AC_Code:

    牛客上现在可以提交了,第一份代码爆内存了,另外两份都可以ac

    //这份代码常数应该挺大,注意优化一下
    
    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long LL;
    
    const int MXN = 1e5 + 5;
    
    int n, m;
    LL dp[101][101][5052];
    struct lp{
        int a, b, c;
    }cw[105];
    
    int main(int argc, char const *argv[]) {
        int tim; scanf("%d", &tim);
        while(tim --) {
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i) {
                scanf("%d%d%d", &cw[i].a, &cw[i].b, &cw[i].c);
            }
            memset(dp, -1, sizeof(dp));
            dp[n][1][n] = cw[n].a;
            int tmp = n*(n+1)/2;
            for(int i = n-1; i >= 1; --i) {
                for(LL j = n-i+1,a=cw[i].a,b=cw[i].b,c=cw[i].c; j >= 1; --j) {
                    for(int k = tmp; k >= n; --k) {
                        if(dp[i+1][j][k] != -1) dp[i][j][k] = dp[i+1][j][k]+max(c*j, b*(k-i*j));
                        if(k >= i+n &&j >= 2&& dp[i+1][j-1][k-i] != -1)
                            dp[i][j][k] = max(dp[i][j][k], dp[i+1][j-1][k-i]+a);
                    }
                }
            }
            LL ans = 0;
            for(int i = 1; i <= n; ++i) {
                for(int j = 1; j <= tmp; ++j) {
                    ans = max(ans, dp[1][i][j]);
                }
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    滚动数组:

    #include<bits/stdc++.h>
    #define A cw[i].a
    #define B cw[i].b
    #define C cw[i].c
    using namespace std;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const int MXN = 1e5 + 7;
    
    int n, m;
    struct lp{
        LL a, b, c;
    }cw[105];
    LL dp[5051][101];
    
    int main() {
        int tim; scanf("%d", &tim);
        while(tim --) {
            scanf("%d", &n);
            m = n*(n+1)/2;
            for(int i = 0; i <= m; ++i) {
                for(int j = 0; j <= n; ++j) {
                    dp[i][j] = -1;
                }
            }
            for(int i = 1; i <= n; ++i) scanf("%lld%lld%lld", &A, &B, &C);
            dp[n][1] = cw[n].a;
            //dp[0][0] = 0;
            for(int i = n-1; i >= 1; --i) {
                for(int k = m; k >= n; --k) {
                    for(int j = n-i+1; j >= 1; --j) {
                        if(dp[k][j] != -1) dp[k][j] += max(j*C,(k-i*j)*B);
                        if(k-i>=n&&j>=2&&dp[k-i][j-1] != -1) {
                            dp[k][j] = max(dp[k][j], dp[k-i][j-1] + A);
                        }
                    }
                }
            }
            LL ans = 0;
            for(int i = 1; i <= m; ++i) {
                for(int j = 1; j <= n; ++j) {
                    ans = max(ans, dp[i][j]);
                }
            }
            printf("%lld
    ", ans);
        }    
        return 0;
    }
    

    如果你不会滚动数组,也可以这样优化空间:

    #include<bits/stdc++.h>
    #define A cw[i].a
    #define B cw[i].b
    #define C cw[i].c
    using namespace std;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const int MXN = 1e5 + 7;
    
    int n, m;
    struct lp{
        LL a, b, c;
    }cw[105];
    LL dp[5051][101][2];
    
    int main() {
        int tim; scanf("%d", &tim);
        while(tim --) {
            scanf("%d", &n);
            m = n*(n+1)/2;
            for(int i = 0; i <= m; ++i) {
                for(int j = 0; j <= n; ++j) {
                    dp[i][j][0] = dp[i][j][1] = -1;
                }
            }
            for(int i = 1; i <= n; ++i) scanf("%lld%lld%lld", &A, &B, &C);
            dp[n][1][0] = cw[n].a;
            //dp[0][0][0] = 0;
            int p = 1, q = 0;
            for(int i = n-1; i >= 1; --i) {
                for(int k = m; k >= n; --k) {
                    for(int j = n-i+1; j >= 1; --j) {
                        if(k-i>=n&&j>=2&&dp[k-i][j-1][q] != -1) dp[k][j][p] = dp[k-i][j-1][q] + A;
                        if(dp[k][j][q] != -1) {
                            dp[k][j][p] = max(dp[k][j][p], dp[k][j][q]+max(j*C,(k-i*j)*B));
                        }
                    }
                }
                p = !p; q = !q;
            }
            LL ans = 0;
            for(int i = 1; i <= m; ++i) {
                for(int j = 1; j <= n; ++j) {
                    ans = max(ans, dp[i][j][q]);
                }
            }
            printf("%lld
    ", ans);
        }    
        return 0;
    }
    

    Problem Description:

  • 相关阅读:
    sysbench测试
    ab压力测试
    kubernetes之Pod水平自动伸缩(HPA)
    JAVA实现Excel批量导入
    Json对象转为实体对象
    Java Web用Freemarker生成带图片的Word文档
    Spring3 MVC 深入核心研究
    SpringMVC深度探险(四) —— SpringMVC核心配置文件详解
    SpringMVC深度探险(三) —— DispatcherServlet与初始化主线
    SpringMVC深度探险(二) —— SpringMVC概览
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/10138441.html
Copyright © 2011-2022 走看看