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

  

原文地址:https://www.cnblogs.com/pkgunboat/p/11139053.html