http://codeforces.com/contest/366/problem/C
在n个物品中选出若干个,使得sum(a[i]) = k * sum(b[i])
把问题转化一下就是,求sum(a[i] - k * b[i]) = 0的最大的a[i],这个时候已经把a[i]作为价值了
那么怎么去求呢?
一开始因为a[i] - k * b[i]有负数,那么需要fix值,fix = 1000
我只设了dp[v]表示产生这个和值时的最大价值。那么如果能产生这个v值,就需要这个v值能整除fix。因为sigma(a[i] - k * b[i])=0
那么这个v值其实就是若干个fix值相加而已。比如-1,fix后是999。。1,fix后是1001,相加是2000
所以只有v % fix == 0的才能作为贡献。但是有bug。因为你不知道它是多少个数相加得到的v。如果是5个数得到的v,那么需要这个v要整除5 * fix才可以,所以我就用了dp[i][j]表示选了i个数产生j的最大价值。但是这样转移是1e9的,但是水过去了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 1e2 + 20; int a[maxn], b[maxn]; struct node { int w, val; }c[maxn]; const int fix = 1000; int dp[100 + 2][1099 * 100 + 20]; void work() { int n, k; cin >> n >> k; int tot = 0; for (int i = 1; i <= n; ++i) cin >> a[i]; for (int i = 1; i <= n; ++i) { cin >> b[i]; c[i].w = a[i] - k * b[i] + fix; c[i].val = a[i]; tot += c[i].w; } memset(dp, -0x3f, sizeof dp); // cout << -inf << endl; cout << dp[0][0] << endl; dp[0][0] = 0; for (int i = 1; i <= n; ++i) { for (int j = i; j >= 1; --j) { for (int k = tot; k >= c[i].w; --k) { dp[j][k] = max(dp[j][k], dp[j - 1][k - c[i].w] + c[i].val); } } } int ans = -1; for (int i = 1; i <= n; ++i) { for (int j = i * fix; j <= tot; j += fix) { ans = max(ans, dp[i][j]); } } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif IOS; work(); return 0; }
所以这个是二维费用背包问题。
5 9
100 100 100 100 100
100 100 100 100 100
然后这题的正解因该是,分开dp,就是一样的转移问题是a[i] - k * b[i]
然后这些东西有正有负,那么就分开吧,dpup[v]表示整数那堆数,产生v这个数字的最大价值。
那么需要dpup[v] + dpdown[v]
注意有0的情况,0要单独处理一下,因为可能dpup[0]有值,但是dpdown[0]是-inf。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 1e2 + 20; int a[maxn]; int b[maxn]; int c[maxn]; int dpup[100 * 1000 + 20]; int dpdown[100 * 1000 + 20]; void work() { int n, k; cin >> n >> k; int tans = 0; int tot = 100 * 1000; for (int i = 1; i <= n; ++i) { cin >> a[i]; } for (int i = 1; i <= n; ++i) { cin >> b[i]; c[i] = a[i] - k * b[i]; if (c[i] == 0) { tans += a[i]; } } memset(dpup, -0x3f, sizeof dpup); memset(dpdown, -0x3f, sizeof dpdown); // cout << dpup[1] + dpdown[1] << endl; dpup[0] = dpdown[0] = 0; for (int i = 1; i <= n; ++i) { // if (c[i] == 0) continue; if (c[i] > 0) { for (int j = tot; j >= c[i]; --j) { dpup[j] = max(dpup[j], dpup[j - c[i]] + a[i]); } } else { c[i] = -c[i]; for (int j = tot; j >= c[i]; --j) { dpdown[j] = max(dpdown[j], dpdown[j - c[i]] + a[i]); } } } int ans = -1; for (int i = 1; i <= tot; ++i) { ans = max(ans, dpup[i] + dpdown[i]); } if (tans != 0) ans = max(tans, ans); cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif IOS; work(); return 0; }