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");
}
}

浙公网安备 33010602011771号