• 【题解】HEOI2013Eden 的新背包问题


      这题真的神奇了……蜜汁复杂度(`・ω・´)

      应该是一个比较连贯的思维方式:去掉一个物品,那么我们转移的时候不考虑它就好了呗。考虑暴力:每一次都对剩余的n - 1个物品进行多重背包转移,获得答案。既然可以优化,就说明一定有重复计算的地方——画出一张方格图,把不需要的格子涂掉——我们突然发现每一个可以有两部分组成,而两部分可以递推得到!那就很简单了:A[i][]表示选择n ~ i 这些物品能获得的最大值,B[i][]表示选择1~i的物品所能获得的最大值。

      答案就是两部分的AB数组暴力合并即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1500
    #define maxq 300015
    int n, q, W[maxn], V[maxn], w[maxn * 10], v[maxn * 10], T[maxn];
    int cnt, L[maxn], R[maxn], A[maxn][maxn], B[maxn][maxn];
    int M;
    
    struct que
    {
        int num, id, m;
    }Q[maxq];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void Get_A()
    {
        for(int i = n; i >= 1; i --)
        {
            int s = T[i], t = 1;
            L[i] = cnt + 1;
            while(s >= t)
            {
                w[++ cnt] = W[i] * t;
                v[cnt] = V[i] * t;
                s -= t, t *= 2;
            }
            if(s) 
            {
                w[++ cnt] = W[i] * s;
                v[cnt] = V[i] * s;
                s -= t, t *= 2;
            }
            R[i] = cnt;
            memcpy(A[i], A[i + 1], sizeof(A[i + 1]));
            for(int j = L[i]; j <= R[i]; j ++)
                for(int k = M; k >= w[j]; k --)
                    A[i][k] = max(A[i][k], A[i][k - w[j]] + v[j]);            
        }
    }
    
    void Get_B()
    {
        for(int i = 1; i < n; i ++)
        {
            memcpy(B[i], B[i - 1], sizeof(B[i - 1]));
            for(int j = L[i]; j <= R[i]; j ++)
                for(int k = M; k >= w[j]; k --)
                    B[i][k] = max(B[i][k], B[i][k - w[j]] + v[j]);
        }
    }
    
    int main()
    {
        n = read();
        for(int i = 1; i <= n; i ++)
            W[i] = read(), V[i] = read(), T[i] = read();
        q = read();
        for(int i = 1; i <= q; i ++)
        {
            Q[i].num = read() + 1, Q[i].m = read();
            Q[i].id = i;
            M = max(Q[i].m, M);
        }
        Get_A();
        Get_B();
        for(int i = 1; i <= q; i ++)
        {
            int k1 = Q[i].num + 1, k2 = Q[i].num - 1;
            int j = Q[i].m, ans = 0;
            for(int a1 = 0; a1 <= j; a1 ++)
                ans = max(ans, A[k1][a1] + B[k2][j - a1]);
            printf("%d
    ", ans);
        }
        return 0;
    } 
  • 相关阅读:
    【转】MFC中png格式图片贴图的实现
    【转】Windows 中不规则窗体的编程实现
    【转】MFC添加背景图片方法的三种方法
    【转】mfc win7获得管理员权限 使用WIN7风格 使用当前系统风格
    【转】双缓冲讲解及界面贴图
    【转】[内核/驱动]驱动中获取进程全路径和注册表全路径
    【转】Visual C++中DDB与DIB位图编程全攻略(转)
    【转】vs2010中添加splashScreen
    【转】一个在内存里搜索QQ号码的源码,源自看雪论坛
    输出JSON
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8994059.html
Copyright © 2020-2023  润新知