其他分享
首页 > 其他分享> > 模拟赛-物品

模拟赛-物品

作者:互联网

物品

题意

有 \(2m+1\) 种物品,重量分别为 \(-m,-m+1,\ldots, m-1,m\)。重量为 \(i\) 的物品有 \(a_i\) 个。

你需要拿走若干物品,使得这些物品重量之和恰好为 \(l\)。在此基础上,你需要拿尽可能多的物品。

问在物品重量之和恰好为 \(l\) 的基础上,你最多能拿多少物品。

题解

先贪心的选出来,然后发现这个东西还剩下不大于 \(m\) 的体积,考虑到再用背包dp剩下的,因为是在 \([L - m, L + M]\) 这个位置,每个位置不会经过超过一次,所以每个物品不超过 \(2M + 1\) 个,然后还有就是,所以体积不超过 \(O(M ^ 2)\) 的。

然后就是对于这 \(2M + 1\) 的背包用一个多重背包优化。

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 610, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
void add(int &x, int y) {if ((x += y) >= MOD) x -= MOD;}
int N, M, K;
ll f[MAXN * MAXN];
ll ans, L, A[MAXN], B[MAXN], D[MAXN], C[MAXN];
// 贪心 O(M ^ 2) 体积 背包。
int main() {
	freopen("goods.in", "r", stdin);
	freopen("goods.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	auto no = [&] () {puts("impossible"), exit(0);};
	qwq::init(20050112);
	read(N, L);
	for (int i = N; i >= 1; --i) read(A[i]), ans += A[i], L += i * A[i];
	ll x;
	read(x);
	ans += x;
	for (int i = 1; i <= N; ++i) read(B[i]);
	if (L < 0) no();
	for (int i = 1; i <= N; ++i) {
		if (B[i] * i <= L) L -= B[i] * i, ans += (D[i] = B[i]);
		else {
			ans += (D[i] = L / i);
			L %= i;
			break;
		}
	}
	for (int i = N; i >= 1; --i) {
		if (A[i] * i <= L) L -= A[i] * i, ans -= (C[i] = A[i]);
		else {
			ans -= (C[i] = L / i);
			L %= i;
			break;
		}
	}
	K = (M = N * N) * 2;
	if (L > M) no();
	memset(f, 207, sizeof f);
	f[M] = 0;
	auto add1 = [&] (int v, int w) -> void {for (int i = K - v; i >= 0; --i) chkmax(f[i + v], f[i] + w);};
	auto add2 = [&] (int v, int w) -> void {for (int i = v = -v; i <= K; ++i) chkmax(f[i - v], f[i] + w);};
	auto mfy = [&] (ll s, int v, int w) -> void {
		// assert(s);
		// [L - N, L + N]
		// 最多删加 2N 次
		// 不超过 O(N) 个物品。
		chkmin(s, N + N + 1LL);
		// assert(v);
		if (v > 0) {
			for (int i = 1, V = v, W = w; i <= s; i <<= 1, V <<= 1, W <<= 1) add1(V, W), s -= i;
			if (s) add1(v * s, w * s);
		} else {
			for (int i = 1, V = v, W = w; i <= s; i <<= 1, V <<= 1, W <<= 1) add2(V, W), s -= i;
			if (s) add2(v * s, w * s);
		}
	};
	for (int i = 1; i <= N; ++i) {
		if (D[i]) mfy(D[i], -i, -1);
		if (B[i] - D[i]) mfy(B[i] - D[i], i, 1);
		if (C[i]) mfy(C[i], -i, 1);
		if (A[i] - C[i]) mfy(A[i] - C[i], i, -1);
	}
	// O(ans);
	if (f[M + L] < -M) no();
	else printf("%lld\n", ans + f[M + L]);
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

标签:std,ch,return,int,void,物品,using,模拟
来源: https://www.cnblogs.com/siriehn-nx/p/16535326.html