题意: 有两大类物品, 第一类物品的价值均为K1, 第二类物品的价值均为K2。
背包容量为c。
每组数据的第三行代表第一类物品的体积,第四行代表第二类物品体积。
对于背包的贡献计算方式为 ( 当前容量 - 选取物品的体积) * 物品种类的价值。
由于容量C太大,所以肯定是不能背包来做。
所以可以考虑dp[i][j] ( i 代表第一类物品选了i个 , j 代表第二类物品选了j个)。
think: 首先简化这个问题, 只选一种物品, 那肯定优先选体积小的,因为价值相同。
所以可以先排下序,预处理出 两种物品的前缀和 与 dp[i][0] 与 dp[0][j]
然后根据容量转移一下。
#include <bits/stdc++.h>
#define ll long long
#define ms(x) memset(x, 0, sizeof(x))
using namespace std;
const int N = 2003;
ll dp[N][N];
ll suma[N], sumb[N];
ll a[N], b[N];
int main()
{
int T;
scanf("%d", &T);
while(T--){
ll k1, k2, c;
int n, m;
scanf("%lld%lld%lld",&k1, &k2, &c);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld", &a[i]);
}
for(int i=1;i<=m;i++){
scanf("%lld", &b[i]);
}
sort(a+1, a+n+1);sort(b+1, b+m+1);
suma[0] = 0; sumb[0] = 0;
for(int i=1;i<=n;i++){
suma[i] = a[i] + suma[i-1];
}
for(int i=1;i<=m;i++){
sumb[i] = b[i] + sumb[i-1];
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
dp[i][j] = 0;
ll ans = 0;
for(int i=1;i<=n;i++){
if(c>=suma[i])
dp[i][0] = dp[i-1][0]+(c - suma[i])*k1;
ans = max(ans, dp[i][0]);
}
for(int i=1;i<=m;i++){
if(c>=sumb[i])
dp[0][i] = dp[0][i-1]+(c - sumb[i])*k2;
ans = max(ans, dp[0][i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(c >= sumb[j]+suma[i]){
dp[i][j] = max(dp[i][j], dp[i][j-1] + k2*(c - sumb[j] - suma[i])),
dp[i][j] = max(dp[i][j], dp[i-1][j] + k1*(c - suma[i] - sumb[j]));
}
else if(c>= suma[i] + sumb[j-1]){
dp[i][j] = max(dp[i][j], dp[i][j-1]);
}
else if(c>= suma[i-1] + sumb[j]){
dp[i][j] = max(dp[i][j], dp[i-1][j]);
}
ans = max(ans, dp[i][j]);
}
}
printf("%lld\n", ans);
}
return 0;
}