专栏文章

题解:CF601E A Museum Robbery

CF601E题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqj7lg8
此快照首次捕获于
2025/12/04 05:41
3 个月前
此快照最后确认于
2025/12/04 05:41
3 个月前
查看原文
Happy New Year!

Solution

删除任意编号的存在物品,不强制在线,先扔一个线段树分治上去。
发现是背包,想到猫树。背包是典型的合并复杂度非常高的信息。发现我们能承受的复杂度是加入一个物品的 O(k)O(k),而非合并两个背包的 O(k2)O(k^2)
另一个有趣的性质是背包信息支持撤销。
那比起在每个节点维护物品构成的背包,我们选择类似 dfs() 的过程,每次加入物品然后继续递归,回溯的时候撤销即可。算是利用上“保证物品总数不超过 1e41e4”的条件了。
时间复杂度 O(nklogq)O(nk\log q)

Code

CPP
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define fi first
#define se second
#define mkp make_pair

const int maxn = 3e4 + 5, maxm = 1e3 + 5;

int n, k, q, op[maxn];
int L[maxn], R[maxn]; pii a[maxn];

vector<pii> t[maxn << 2];

#define ls (x << 1)
#define rs (x << 1 | 1)

inline void updtr(int x, int l, int r, int L, int R, pii v){
	if(l >= L and r <= R) return t[x].push_back(v), void();
	int mid = l + r >> 1;
	if(L <= mid) updtr(ls, l, mid, L, R, v);
	if(R > mid) updtr(rs, mid + 1, r, L, R, v);
}

const ll p = 1e7 + 19, mod = 1e9 + 7;

ll st[maxn][maxm], ans[maxn]; int tp;

inline void qry(int x, int l, int r){
	int tp0 = tp;
	for(auto nw : t[x]){
		++tp; 
		rep(i, 1, k) 
			st[tp][i] = max(st[tp - 1][i], i >= nw.se ? st[tp - 1][i - nw.se] + nw.fi : 0ll);
	}
	int mid = l + r >> 1;
	if(l == r){
		if(op[l] == 3){
			ll fac = 1ll; 
			rep(m, 1, k) 
				(ans[l] += st[tp][m] * fac % mod) %= mod, (fac *= p) %= mod;
		}
		goto bre;
	}
	qry(ls, l, mid); qry(rs, mid + 1, r);
	bre:;
	while(tp != tp0) --tp;
}

signed main(){
	ios_base::sync_with_stdio(0); cin.tie(NULL);
	
	cin >> n >> k;
	rep(i, 1, n) cin >> a[i].fi >> a[i].se;
	cin >> q;
	rep(i, 1, n) L[i] = 1, R[i] = q;
	rep(i, 1, q){
		cin >> op[i];
		if(op[i] == 1){
			++n; cin >> a[n].fi >> a[n].se;
			L[n] = i, R[n] = q;
		}
		if(op[i] == 2){
			int x; cin >> x; R[x] = i;
		}
	}
	rep(i, 1, n) updtr(1, 1, q, L[i], R[i], a[i]);
	qry(1, 1, q);
	rep(i, 1, q) if(op[i] == 3) cout << ans[i] << '\n';
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...