NOIP模拟赛 #10
A
猜结论。
B
有 \(n\) 堆硬币,每堆有 \(3\) 枚,第 \(i\) 堆硬币从上到下价值分别为 \(a_i, b_i, a_i\)。取若干个硬币,要求每堆必须先取上面再取下面,求分别取 \(1, 2, 3, \dots, k\) 枚硬币时的最大价值和。
\(1\le n\le 5\times 10^6, \ 1\le k\le 3n\)
对于第 \(i\) 堆,可以转化为一个价值为 \(a_i\) 的物品,体积为 \(1\),以及一个价值为 \(a_i + b_i\) 的物品,体积为 \(2\),发现所有组合情况恰好对应这堆硬币取 \(0, 1, 2, 3\) 枚时的价值。
所以我们只需要对体积为 \(1\) 或 \(2\) 的一些物品进行背包,求出体积之和恰好为 \(1, 2, 3, \dots, k\) 时的答案。考虑钦定只取体积为 \(1\) 的物品,反悔取体积为 \(2\) 的物品即可。
C
给定一个由至多 \(10\) 种小写字母组成的字符串,多次询问,求一个一个区间内本质不同子序列数量,答案模 \(10^9 + 7\)。
\(1\le n, q\le 5\times 10^5\)
考虑猫树分治。对于一个子序列,在原串中匹配该子序列,映射到最小表示上。
对于一个分治节点 \((l, r, mid)\),对于一个询问 \([l_q, r_q]\) 满足 \(l\le l_q\le mid < r_q\le r\),若只用匹配 \([l_q, mid]\) 匹配是容易的。否则考虑枚举 \([mid + 1, r_q]\) 匹配的第一个字符 \(c\),对于 \(l\le i\le mid\) 设 \(f_{i, c}\) 表示从匹配到了第 \(i\) 位,在左半部分后续匹配且 \([\text{左半部分最后一个匹配位置} + 1, mid]\) 中没有字符 \(c\) 的方案数,对于 \(mid + 1\le i\le r\) 设 \(g_{i, c}\) 右半部分开头匹配到了位置 \(i\) 且第一个匹配的字符是 \(c\) 的方案数,那么对答案的贡献为 \(f_{l_q - 1, c}\sum_{i = mid + 1} ^ r g_{i, c}\)。
对于 \(f, g\),可以直接差分 / 前缀和优化求出,时间复杂度 \(\mathcal O(10n\log n)\)。
D
你需要依次 \(n\) 件商品,第 \(i\) 件商品需要花费 \(a_i\) 个金币。你可以使用一张优惠券代替一枚金币,买商品 \(i\) 使用的优惠券数量应不超过 \(b_i\)。初始时你有 \(m\) 张优惠券,当你买商品 \(i\) 时使用了 \(x\) 张优惠券,则购买后可以获得 \(\dfrac {a_i - x} c\) 张优惠券,\(c\) 为给定常数,求使用的最少金币总数。
\(1\le n\le 10^6, \ 0\le m, a_i, b_i\le 10^9, \ 2\le c\le 10^9\)
考虑商品 \(i\) 该如何合理使用优惠券:
-
首先使用 \([0, a_i \bmod c]\) 张优惠券,此时不影响获得的优惠券数量,性价比最高。
-
接着使用 \(k \cdot c\) 张优惠券,会损失 \(k\) 张优惠券的获得。
-
最后使用 \([0, c - 1]\) 张优惠券,会损失 \(1\) 张优惠券的获得。
不难发现三种方式有着严格的优先级。先处理第一种方式,设 \(x_i\) 为商品 \(i\) 使用的优惠券数量,设 \(s_i\) 为买完商品 \(1\sim i\) 后剩下的优惠券数量,那么 \(x_i = \min(s_{i - 1}, b_i, a_i \bmod c)\)。
然后是第二种,不难发现对应的商品越靠后越好,考虑从后往前处理,则 \(x_i \gets x_i + c \cdot \min \left(\left \lfloor \dfrac {b_i - x_i} c \right \rfloor, \left \lfloor \dfrac {s_{i - 1} - x_i} c \right \rfloor, \min_{j = i + 1} ^ n \left \{ \left \lfloor \dfrac {s_{j - 1} - x_j} {c + 1} \right \rfloor \right \} \right)\),第三者可以通过维护后缀 \(\min\) 解决。
最后是第三种方式,不难发现操作的商品数量越少越好,可以优先操作可使用优惠券数量尽量多的商品。商品 \(i\) 可使用的优惠券数量为 \(\min(b_i - x_i, s_{i - 1} - x_i, \min_{j = i + 1} ^ n \{ s_{j - 1} - x_j - 1 \})\)。设 \(t_i = s_{i - 1} - x_i\),则原式为 \(\min(b_i - x_i, t_i, \min_{j = i + 1} ^ n \{ t_j - 1 \})\)。
一种暴力的方法是从大到小枚举单个商品使用优惠券数为 \(w\),然后检查每个商品是否可以操作。注意到 \(\min(t_i, \min_{j = i + 1} ^ n \{ t_j - 1 \})\) 随着 \(i\) 变大而变大,只需要注意 \(b_i - x_i\) 即可。
考虑所有商品按照 \(b_i - x_i\) 从大到小依次加入,设当前商品和下一个商品的 \(b_i - x_i\) 分别为 \(p, q\),可以处理掉 \(w \in [q + 1, p]\)。维护一个堆维护合法的位置 \(i\) 的集合,每次取出最大的合法位置,检查是否满足条件,查询可以使用线段树维护 \(t\) 的区间最小值,以及支持区间加。
- 启示:贪心,分层,分逻辑。