P1782 旅行商的背包
2024年10月25日大约 3 分钟
P1782 旅行商的背包
题目描述
小 S 坚信任何问题都可以在多项式时间内解决,于是他准备亲自去当一回旅行商。在出发之前,他购进了一些物品。这些物品共有
然而,就在他出发前,他又收到了一批奇货。这些货共有
输入格式
第一行三个数
以下
以下
输出格式
仅一行,为最大的价值。
说明/提示
样例解释
前两种物品全部选走,最后一个奇货分给
限制与约定
对于
思路
普通物品可以用单调队列的多重背包,奇货采用暴力拆分,先dp普通物品,再dp奇货
dp奇货的过程暴力递推大概是
x_x AC,WA,TLE五颜六色
看了下AC的大佬说这个卡时间很紧,max和deque之类的都会拖后腿,另外这题可能单调队列跑不过二进制
下面换二进制试试
改成二进制AC了
题解
#include <iostream>
#include <deque>
#include <cstring>
#define debug(x) #x << ":" << x << " "
#define ll long long
using namespace std;
ll dp[2][12800];
int now = 0;
struct
{
ll v; // 体积
ll w; // 价值
ll d; // 数量
} goods[12800];
struct
{
ll a, b, c;
} odd[16];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n, m, C;
cin >> n >> m >> C;
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
{
cin >> goods[i].v >> goods[i].w >> goods[i].d;
}
for (int i = 0; i < m; i++)
{
cin >> odd[i].a >> odd[i].b >> odd[i].c;
}
// 二进制优化
for (int i = 0; i < n; i++)
{
int s = goods[i].d;
for (int c = 1; s >= c; s -= c, c <<= 1)
{
int now_v = goods[i].v * c;
int now_w = goods[i].w * c;
for (int j = C; j >= now_v; j--)
{
dp[now][j] = max(dp[now][j], dp[now][j - now_v] + now_w);
}
}
if (s != 0)
{
int now_v = goods[i].v * s;
int now_w = goods[i].w * s;
for (int j = C; j >= now_v; j--)
{
dp[now][j] = max(dp[now][j], dp[now][j - now_v] + now_w);
}
}
}
for (int i = 0; i < m; i++)
{
int pre = now;
now = 1 - now;
for (int j = 0; j <= C; j++)
{
dp[now][j] = dp[pre][j];
for (int x = 0; x <= j; x++) // 即使x = 0,也有c,所以x为0也要考虑
{
dp[now][j] = max(dp[now][j], dp[pre][j - x] + odd[i].a * x * x + odd[i].b * x + odd[i].c);
}
}
}
cout << dp[now][C];
return 0;
}