奇怪的问题(们)
奇怪的背包(们)
CQ友谊赛 - pack
\(n\leq 100\)。物品体积 \(\leq 100\),权值很大 \((\leq 10^9)\)。\(m(\leq 100)\) 次询问,求体积恰好为 \(q(\leq 10^9)\) 时的最大物品价值和方案数(相同的物品间没有顺序之分,不同的物品间有顺序之分。)
物品体积 \(\leq 100\) 是突破口。设 \(f_i=(a,b)\) 表示体积恰好为 \(i\) 时最大价值为 \(a\) 方案数为 \(b\)。一个物品设为 \((v_i,1)\) (\(v_i\) 是体积。)有转移 \(f_{i+w_j}=f_{i+w_j}+f_i \times (v_j,1)\)。其中二元组加法就类似线段树维护最小值个数时 pushup 的操作。二元组乘法就是 \(a\) 相加,\(b\) 相乘。发现这个是对的,而且可以放到矩阵上。直接矩阵快速幂优化就做完了。
[THUPC 2023 初赛] 背包
\(10^{11} \leq V \leq 10^{12}\) 是突破口。体积下界大得离谱!显然要选一堆性价比最高的。总而言之地引用一句话,“发现 \(V\) 很大 \(v_i\) 却很小,而且还是完全背包,一般都是同余最短路。”
设我们一开始选择了 \(\lfloor \frac{V}{v_0} \rfloor\) 个最优物品,其中 \(v_0\) 是最优物品的体积。设 \(f_i\) 表示,选择体积 \(\bmod v_0 = i\) 时的最优增量。什么意思呢?假设选了一个其它物品,让 \(i+v_j\) 超过了 \(v_0\),那么此时就需要少选一些最优物品让总体积不超过 \(V\),即还要减去 \(\lfloor \frac{i+v_j}{v_0} \rfloor \times w_0\)。这样最后再加上 \(f_{V\bmod v_0}\) 就是答案。求 \(f\) 直接跑最长路就行了。
这显然是对的。我们不可能让最优物品数量变成负。因为最长路不可能经过同一个节点,一旦经过了就说明中间加入的体积 \(\bmod v_0 = 0\),这样就一定不优。当每一个节点只经过一次,总共只会加入 \(v^2\) 的额外体积,这显然是 \(\leq 10^{10}\) 的,而且小于 \(V\) 的下界 \(10^{11}\)。于是它就是对的了。
P4495 [HAOI2018] 奇怪的背包
兄啊,这题和背包有任何关系吗?(全恼。)
20251119模拟赛 - 物品分类
\(type=1,2,3\) 是 EASY 的。直接猜猜结论统计一下就做完了。如果只有这三个 \(type\) 完全可以放达摩院模拟赛 T1。
\(type=4\) 是 HARD 的。考虑如何去简单地刻画 \(g(p)\),从而让其能够被计数。这是 HARD 的,但是我们还是能发现 \(g(p)=len(p)-cnt(p)-[cnt(p)=len(p)-1]\)。其中 \(cnt(p)=\min(L_p,R_p)\),其中 \(L_p\) 为 \(p\) 最长的元素互不相同的前缀的长度,\(R_p\) 为 \(p\) 最长的元素互不相同的后缀的长度。这是相当不显然的,\([L_p+1,len(p)]\) 显然是一个合法的垃圾子序列对应的子串,因为 \(p\) 中的第 \(L_p+1\) 个元素是第一个在前缀中重复出现的元素,而且还能知道不存在一个更长的后缀满足它很垃圾。同理 \([1,len(p)-R(p)]\) 也是一个合法的前缀。(我们显然可以证明一个对应的子串不是前/后缀的垃圾子序列一定不是最长的。)然后显然那个表达式就是对的了,不再赘述。
所以现在要统计 \(\sum len(p)\),\(\sum cnt(p)\) 和 \(\sum [cnt(p)=len(p)-1]\)。式 \(1\) 和式 \(3\) 都是好做的。主要来考虑式 \(2\)。对每个子序列直接算 \(cnt(p)\)?枚举 \(cnt(p)\) 然后统计方案数?发现这个东西 とても HARD!(ハヅ!)不过统计 \(\geq cnt(p)\) 的方案数看起来就比较简单了,因为不需要满足它恰好了。
具体地,枚举 \(p\) 的第 \(k\) 个位置 \(l\) 和其倒数第 \(k\) 个位置 \(r\)。假设 \(l\leq r\),那么只需要满足 \(l\) 左边选择了 \(k-1\) 个不同的,\(r\) 右边选择了 \(k-1\) 个不同的就能保证 \(cnt(p)\geq k\) 了。对于每一个 \(k\) 计算这种方案数再加起来就是答案。这是一个经典的反演。中间选择的方案数就是 \(2^{r-l-1}\)。需要处理的只有 \(F(l-1,k-1)\) 和 \(G(r+1,k-1)\),分别表示 \([1,l-1]\) 中选择 \(k-1\) 个不同元素的方案数和 \([r+1,n]\) 中选择 \(k-1\) 个不同元素的方案数。发现可以直接预处理 \(F_{i,j}\) 和 \(G_{i,j}\),使用背包。相当于我有若干个体积为 \(1\),方案数为 \(cnt\) 的物品(表示选择哪一个),然后统计体积为 \(j\) 时的所有方案。不过假设现在要加入一个物品,它对应的方案数(即出现次数)可能改变,这个时候直接暴力重新插入,反正每个前缀只有 \(O(n)\) 个物品,时间复杂度 \(O(n^3)\)。需要保证加入的元素和 \(a_{i+1}\) 不同。(我们定义一场比赛里有宝藏题目和垃圾题目,发现这个题就是垃圾题目。)
如果 \(l>r\),就非常的魔怔。魔怔啊!魔怔。魔怔啊!魔怔。从刚刚那种情况可以看出,问题已经和 \(k\) 本身无关了。现在 \(l\) 和 \(r\) 将原序列分成了三段,那么我们其实只需要统计段 \(1\) 和段 \(3\) 选择物品数量相同的方案数!此时一个物品变成了一个分组背包!对的。怎么回滚?
咕咕嘎嘎!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
垃圾题目!!!!
从这个题目中,我学习到了一个东西。若当前有若干体积为 \(v_i\) 权值为 \(w_i\) 的物品,定义一个物品选择方案的权值为所有选择物品权值的乘积,求所有体积为 \(j\) 的物品选择方案的权值之和。这个东西用背包做显然可以做,而且更重要的是:它可以支持删除任意一个物品!
具体理解方式是,这个背包的生成函数显然是 \(\prod (1+w_ix^{v_i})\),删掉一个物品就是除以一个式子,显然可以做,而且是线性的,直接递推一下就行了。(可能带 \(\log\)。)
学长讲过的问题(们)(也许?)
P12912 [POI 2020/2021 R2] 收拾背包 / Pakowanie plecaka
奇怪的树形 DP
DFS 序合并
假设现在一个物品有三种体积权值,需要求选一个连通块满足体积和为 \((a,b,c)\) 时的方案数,直接树形背包可以做到 \(O(na^2b^2c^2)\),因为合并背包是 \(O(a^2b^2c^2)\) 的。
但是呢,加入一个物品的复杂度是 \(O(abc)\) 的。这启示我们使用 DFS 序合并。设 \(dp_{i,a,b,c}\) 为考虑到 DFS 序为 \(i\) 的点时,体积为 \((a,b,c)\) 时的方案数(此时 \(i\) 还没选择)。如果要选择点 \(i\),就转移到 \(dp_{i+1}\),否则点 \(i\) 的整棵子树都选不了,直接转移到 \(dp_{Out_i+1}\)。这样复杂度就能做到 \(O(nabc)\) 了。但仔细思考发现,如果不选根的话,整个树都不能选,也就是说这是钦定了根节点必须选的时候的方案数!如果不选根怎么办?加一个点分治就行了,时间复杂度 \(O(n\log nabc)\)。
合法的连通块?
假设一个连通块(集合)的合法判定条件只跟一个子连通块有关,并且我们对子连通块中的每个点的要求独立,那么如果统计子连通块的点数-边数,算出来的答案就是对的。具体的,对于一个点,我们统计它合法时包含它的连通块个数,再对于一条边去统计它两端点都合法时包含它的连通块个数,减一减即为答案。(这显然是对的。)
经典应用就是,求连通块个数为 \(K\) 的连通块集合个数,需要满足这些连通块至少有一个交点。对一个点,合法的条件就是它被包含。因此,只需要统计包含一个点的连通块方案数和包含一条边的连通块方案数就行了,这个用 DFS 序直接做(因为已经钦定了至少一个被包含的点)。然后可能要算个非常离谱的组合数,需要模数有一点特殊性质才行,不过这不是重点吧应该。

浙公网安备 33010602011771号