Codeforces 356D 倍增优化背包
题目链接:http://codeforces.com/contest/356/problem/D
思路(官方题解):http://codeforces.com/blog/entry/9210
此题需要注意,直接用01背包会TLE, 需要看成多重背包,倍增优化一下。
代码:
#include <bits/stdc++.h> #define LL long long #define pii pair<int, int> using namespace std; const int maxn = 70010; bitset<maxn> dp; pii a[maxn]; int ans[maxn], pre[maxn], numl[maxn], numr[maxn], cnt[maxn]; vector<int> re[maxn]; set<pii> s; set<pii>::iterator it; bool v[maxn]; int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i].first); a[i].second = i; cnt[a[i].first]++; } sort(a + 1, a + 1 + n); reverse(a + 1, a + 1 + n); dp[a[1].first] = 1; cnt[a[1].first]--; int pos = -1; for (int i = 2; i <= n && dp[m] == 0; i++) { int t = cnt[a[i].first]; for (int k = 1; t; k <<= 1) { k = min(t, k); for (int j = m; j >= a[1].first + a[i].first * k; j--) { if(dp[j] == 0 && dp[j - a[i].first * k] == 1) { dp[j] = 1; numl[j] = i, numr[j] = i + k - 1; pre[j] = j - a[i].first * k; } } t -= k; i += k; if(dp[m] == 1) { pos = i; break; } } i--; } if(dp[m] == 0) { printf("-1\n"); return 0; } for (int i = m; i > a[1].first; i = pre[i]) { for (int j = numl[i]; j <= numr[i]; j++) { v[j] = 1; s.insert(a[j]); } } s.insert(a[1]); v[1] = 1; for (int i = 1; i <= n; i++) { if(v[i]) continue; it = s.lower_bound(make_pair(a[i].first, -1)); pii tmp = *it; s.erase(it); tmp.first -= a[i].first; ans[tmp.second] -= a[i].first; re[tmp.second].push_back(a[i].second); s.insert(tmp); s.insert(a[i]); } for (int i = 1; i <= n; i++) { ans[a[i].second] += a[i].first; } for (int i = 1; i <= n; i++) { printf("%d ", ans[i]); printf("%d", re[i].size()); for (int j = 0; j < re[i].size(); j++) { printf(" %d", re[i][j]); } printf("\n"); } }