题目链接:https://www.luogu.org/problemnew/show/P1782
时空限制 1000ms-2000ms / 128MB

题目描述

小S坚信任何问题都可以在多项式时间内解决,于是他准备亲自去当一回旅行商。在出发之前,他购进了一些物品。这些物品共有n种,第i种体积为Vi,价值为Wi,共有Di件。他的背包体积是C。怎样装才能获得尽量多的收益呢?作为一名大神犇,他轻而易举的解决了这个问题。

然而,就在他出发前,他又收到了一批奇货。这些货共有m件,第i件的价值Yi与分配的体积Xi之间的关系为:Yi=ai*Xi^2+bi*Xi+ci。这是件好事,但小S却不知道怎么处理了,于是他找到了一位超级神犇(也就是你),请你帮他解决这个问题。

输入格式

第一行三个数n,m,C,如题中所述;
以下n行,每行有三个数Vi,Wi,Di,如题中所述;
以下m行,每行有三个数ai,bi,ci,如题中所述。

输出格式

仅一行,为最大的价值。

输入样例

2 1 10
1 2 3
3 4 1
-1 8 -16

输出样例

10

说明

【数据范围】
对于100%的数据,1≤n≤10,000,1≤m≤5,1≤C≤10000,
1≤Wi,Vi,Di≤1000,-1000≤ai,bi,ci≤1000.
【样例解释】
前两种物品全部选走,最后一个奇货分给4的体积,收益为2*3+4*1+-1*16+8*4+-16=10。
时限3s

解题思路

这题就是简单的多重背包,外加枚举奇货的体积。 
Accepted Code:

#include <bits/stdc++.h>
using namespace std;
int c, dp[10005];
void ZeroOnePack(int w, int v) {
    for (int i = c; i >= v; i--)
        dp[i] = max(dp[i], dp[i - v] + w);
}
void CompletePack(int w, int v) {
    for (int i = v; i <= c; i++)
        dp[i] = max(dp[i], dp[i - v] + w);
}
void MultiplePack(int v, int w, int m) {
    if (v * m >= c) {
        CompletePack(w, v);
        return ;
    }
    int k = 1;
    while (k < m) {
        ZeroOnePack(w * k, v * k);
        m -= k;
        k <<= 1;
    }
    ZeroOnePack(w * m, v * m);
}
int main() {
    int n, m, v, w, d, ai, bi, ci;
    scanf("%d%d%d", &n, &m, &c);
    for (int i = 0; i < n; i++) {
        scanf("%d%d%d", &v, &w, &d);
        MultiplePack(v, w, d);
    }
    for (int i = 0; i < m; i++) {
        scanf("%d%d%d", &ai, &bi, &ci);
        for (int j = c; j >= 0; j--)
            for (int k = 0; k <= j; k++)
                dp[j] = max(dp[j], dp[j - k] + (ai * k + bi) * k + ci);
    }
    printf("%d\n", dp[c]);
    return 0;
}