做题记录 #2
QOJ7012 Rikka with An Unnamed Temple
给定一个 \(n\) 个点 \(m\) 条边的 DAG,起点为 \(1\) 终点为 \(n\)。点 \(i\) 有一个重量为 \(w_i\) 价值为 \(c_i\) 的物品,经过一条路径会拾取路径上所有物品,路径合法当且仅当物品重量总和 $W \equiv t \pmod k $。对于每个点求不经过该点的合法路径价值最大值以及合法路径数。
\(n \le 10^5,m \le 2 \times 10^5,0 \le t < k \le 100,1 \le w_i,c_i \le 10^9\)。
对于一个 DAG,如果我们已经求出来拓扑序,那么一条路径的拓扑序一定递增。考虑不经过点 \(x\),则合法路径一定存在一条边 \(u \rightarrow v\),拓扑序满足 \(u < x < v\)。那么预处理存在前后缀的点信息,然后枚举每一条边考虑这条边会对哪些点做贡献,不难发现做贡献的点拓扑序是一个区间,线段树标记永久化打标记即可。时间复杂度 \(O((n+m)k + m \log n)\)。
Fun fact:无解需要输出 \(-1\),我的初版代码判无解用的是路径条数 \(=0\),但是数据存在 \(ans \equiv 0 \pmod {10^9 + 7}\)。
[ARC201B] Binary Knapsack
有 \(N\) 个物品,第 \(i\) 个物品重量为 \(2^{X_i}\),价值为 \(Y_i\)。
求背包容量为 \(W\) 时的价值和最大值。
\(1 \le N \le 2 \times 10^5,1 \le W \le 10^{18},0 \le X_i < 60,1 \le Y_i \le 10^9\)。
真青吗?
要求重量和小于等于 \(W\) 有点难,先考虑严格等于 \(W\) 怎么做。
发现当 \(W\) 是奇数的时候,一定会选择价值最大的 \(2^0\) 的物品。然后把 \(2^0\) 物品两两合并变成 \(2^1\) 的物品,可以递归到 \(W/2\) 问题解决。
小于等于怎么做呢,往每个 \(2^X\) 里面插一个价值为 0 的物品即可。复杂度 \(O(n \log n \log W)\)。
[ARC201D] Match, Mod, Minimize
给定两个长度为 \(n\) 的序列 \(A,B\),任意重排使得 \(\max_i (A_i + B_i \mod m)\) 最小,输出最小值。
\(1 \le n \le 3 \times 10^5,1 \le m \le 10^9\)。
场切爽。
如果 \(A_i \rightarrow -A_i\) 然后把 \(A,B\) 都从小到大排序,结论是答案为 \(\min_{0\le j < n} (\max_i (B_i - A_{(i+j) \mod n}) \mod m)\)。挖吧会证,所以讲我的另一个做法。
还是转换为 \(\max (B_i - A_i)\),然后二分答案 \(X\),考虑对于一个 \(A_i\) 而言,与之对应的 \(B_i\) 应当满足 \(B_i \in [A_i,A_i+X]\)。那么,如果把 \(A_i\) 向所有可能作为匹配对象的点连边,答案小于等于 \(X\) 当且仅当建出来的图有完美匹配。考虑 Hall 定理,进而发现排好序后我们可以把一个子集中下标连续的 \(A_{[l,r]}\) 单独独立出来考虑,可以证明独立出来每个区间都满足要求是充要的,所以我们把考虑每个子集变成考虑每个区间。
那么我们现在可以枚举每一个区间来判定了,但是 \(O(n^2 \log m)\) 过不去,考虑加速判定过程。对于一个下标区间 \([l,i]\),它连着的点在 \([A_l,A_i + X]\) 中间。我们惊奇的发现左端点与 \(X\) 无关!记录前缀和数组 \(s\),表示 \(B\) 中小于等于 \(i\) 的数有多少个。对于区间 \([l,i]\),判定条件即为 \(i-l \le s_{A_i+x} - s_{A_l}\),移项得到 \(i-s_{A_i+x} \le l - s_{A_l}\)。
那么枚举右端点 \(i\),在二分答案外面预处理前缀最小值 \(\min_{1\le L < i} (L-s_{A_L})\),即可对每个右端点 \(O(1)\) 找到限制最紧的左端点。相关处理还要离散化,所以会需要使用 std::lower_bound()。时间复杂度 \(O(n \log n \log m)\)。\(n \le 3 \times 10^5,m \le 10^9\) 跑了 800ms。
[ARC201E] Total Area of Bounding Boxes
给定一个排列 \(P\),在坐标系上撒 \(n\) 个点 \((i,P_i)\),定义一个点集的全值为覆盖这个点集所需的最小横平竖直矩形的面积,求点集的所有子集权值和。忽略 \(|S| \le 1\)。
\(2 \le n \le 2 \times 10^5\)。
场切爽。15min 写完 4.3k 代码一遍过爽。
矩形面积太抽象了。对于一个点集 \(S\),权值即为 \((\max_{i \in S}(x_i) - \min_{i \in S}(x_i))(\max_{i \in S}(y_i) - \min_{i \in S}(y_i))\)。同时有 \(\min,\max\) 不好处理,考虑拆开式子,相当于求:
对四种情况分别计算。下面拿 \(\max \times \max\) 举例。
不妨枚举 \(\max X_T = i\),然后算出 \(\sum_{\max X_T \ge i} \max Y_T\) 后,做一个差分算出最大值恰好为 \(i\) 的权值和。设 \(f_i = \sum_{\max X_T \ge i} \max Y_T\),考虑如果我们通过某些手段得知了 \(f_{i+1}\),怎么算 \(f_i\)。
发现每次相当于对一个后缀求解。我们相当于对于上一个后缀的每一个集合,考虑加入 \((i,P_i)\) 的贡献。设 \(P_{(i,n]}\) 中有 \(x\) 个数小于 \(P_i\),相当于 \(P_i\) 会做 \(2^x\) 次方的贡献。而加入 \(P_i\) 对于那些比它大的数没有影响,所以所有比它大的数的贡献翻倍。(之前做贡献的集合,每个可以选择加入或者不加入 \(P_i\))
那么我们建棵线段树,下标为 \(i\) 的节点维护 \(P_i\) 是否出现过和会贡献多少,每次相当于单点改,区间乘二,查询区间次数和或者全局贡献和。这个不难写吧!总复杂度 \(O(n \log n)\)。
感觉我的实现太优美了所以贴份提交记录来自我陶醉。Submission.
CF1422F Boring Queries
给定序列 \(A\),在线查询静态 LCM,输出对 \(10^9 + 7\) 取模。
\(1 \le n \le 10^5,1 \le a_i \le 2 \times 10^5,1 \le q \le 10^5\)。
考虑处理出同一右端点的所有答案。发现对于 \(a_r\) 的所有质因数,它会向左逐步增加。考虑使用主席树维护贡献。加入新的右端点时可能会和之前的贡献算重,所以对于每一个质因数维护一个单调栈,保证次数从栈顶到栈底单调递增。弹出时在位置上乘上对应的逆元贡献即可。质因数出现次数是 \(O(n \log V)\) 量级,所以时间复杂度 \(O(n \log n \log V + q \log n)\)。
P11405 [RMI 2020] 秘鲁 / Peru
给定一个长度为 \(n\) 的序列 \(A\),将序列划分成若干长度不超过 \(K\) 的子区间,一种划分方案的代价是所有子区间的区间 \(\max\) 加起来。对 \(A\) 的每一个前缀求最小划分代价。
\(1 \le K \le n \le 2.5 \times 10^6,1 \le A_i \le 2 \times 10^9\),200ms。
答案单调递增。考虑 dp 解决。转移可以从 \(O(nk)\) 变成维护单调队列,并用可删堆维护队列中的最小值,做到 \(O(n \log k)\),很难通过。
双栈模拟队列。开两个栈,分别处理 front/back 的相关操作。不用可删堆维护最小值了,直接维护每个栈的前缀 \(\min\)。一个栈弹空了怎么办?暴力重构,把另一个栈的节点均匀地分给两个栈。这样子复杂度是 \(O(n)\) 的。
为什么是 \(O(n)\) 的呢?如果当前进行了一次 \(O(siz)\) 的重构,说明下一次重构前需要弹出 \(O(siz)\) 个元素。我们把重构的复杂度均摊到每次弹出计算,就可以得到重构和弹出均为 \(O(1)\)。
P10430 [JOIST 2024] 鱼 3 / Fish 3
给定一个长度为 \(N\) 的序列 \(C\)。有 \(Q\) 次询问,每次询问给出一个区间。你要解决在这个区间 \([l,r]\) 上的如下子问题:
有一个初始全 0 的序列 \(A_l,A_{l+1},\dots,A_{r}\),你可以进行两种操作:
- 单点加 \(D\);
- 后缀加 1。
问能否进行若干次操作,使得 \(A_i = C_i (l \le i \le r)\)。如果可以,给出最少需要的 1 操作次数。
首先把问题转换一下,变成进行若干次减操作,让 \(C\) 区间全变成 0。由于我们不关心第二种操作的次数,所以进一步转换,对区间进行最少几次单点减 \(D\) 操作,使得区间单调不降。
我们记一个高度数组 \(h_i = \lfloor \frac{C_i}{D} \rfloor\),现在变成了在高度数组上面单点减一。但是可能还有模 \(D\) 余数大小问题,额外记一个数组 \(t_i = [C_i \bmod D < C_{i-1} \bmod D]\),那么现在原序列单调不降相当于 \(h_i < h_{i+1} \or (h_i = h_{i+1} \and t_{i+1} = 0)\)。
从小到大枚举右端点然后扫描线,维护当前想要让 \([i,r]\) 满足条件,至少要对 \(h_i\) 减多少。发现可以维护出来若干个连续段 \([x,y]\),满足 \(h_i+t_{i+1} = h_{i+1}\);每次需要进一步操作,都是整个连续段一起操作。考虑两个相邻的连续段 \([a,b),[b,c]\) 啥时候需要合并,可以算出来当前的 \(h_b' = h_c - \sum_{i=b+1}^c t_i\),条件也就是 \(h_{b-1}+t_i \ge h_b'\)。那么每次算出来需要对 \([a,b)\) 再区间减多少次就可以合并了。
维护连续段可以用栈,维护区间加区间求和操作次数可以用线段树。判无解是好判的,对于询问区间查询左端点是否被减为负数即可。合并段次数和查询次数是 \(O(n+q)\) 级别,时间复杂度 \(O((n+q) \log n)\)。
P12445 [COTS 2025] 数好图 / Promet
给定正整数 \(N\) 和素数 \(P\)。\(\forall K=0,1,\ldots,N\),求出满足以下条件的简单有向图的数量对 \(P\) 取模后的结果:
- 图中仅包含 \(i\to j\)(\(1\le i\lt j\le N\))的边;
- 满足以下条件的点 \(u\) 恰好有 \(K\) 个:
- 存在 \(1\to u\) 和 \(u\to N\) 的路径。
\(2\le N\le 2\,000\)。
P4769 [NOI2018] 冒泡排序
给定 \(n\) 和素数 \(P\) 和长度为 \(n\) 的排列 \(q\),求有多少字典序严格大于 \(q\) 的排列 \(p\),满足对这个排列冒泡排序的次数卡在下界 \(\frac{1}{2} \sum_{i=1}^n |i-p_i|\)。
\(n \le 6 \times 10^5\)。
P10004 [集训队互测 2023] Permutation Counting 2
给定 \(n\),对于每组 \(x,y\in [0,n)\) 求出有多少个 \(1\sim n\) 的排列 \(p\) 满足以下条件,答案对给定质数 \(MOD\) 取模。
- \(\sum\limits_{i=1}^{n-1}[p_i<p_{i+1}]=x\)。
- \(\sum\limits_{i=1}^{n-1}[p^{-1}_i<p^{-1}_{i+1}]=y\)。
\(1 \le n \le 500\)。
P11423 [清华集训 2024] 阿尔塔尔 2
交互题。有一个隐藏的 \(n\) 个点的竞赛图。每次可以询问两个点之间的边的方向,最终需要给出一个点,满足从这个点出发到达所有点所需的最大步数是所有点作为起点中最小的。
\(3 \le n \le 300\),需要让询问次数平均值 \(X \le 700\)。
P10441 [JOIST 2024] 乒乓球 / Table Tennis
给定 \(N,M\),你需要构造一个竞赛图,满足这个竞赛图的三元环个数等于 \(M\)。或报告无解。
\(3 \le N \le 5000\)。
P10546 [THUPC 2024 决赛] 采矿
交互题。给定一颗隐藏有向树,每条边有编号。每次询问你可以选择原图上的一些边翻转方向,交互库会给出新图上对于每一个点 \(u\) 有多少个点可以到达它。最终你需要确定这棵树。具体的,你需要给出形如 \(u \rightarrow v\) 的 \(n-1\) 条树边。
\(2 \le n \le 10^4\),需要满足询问次数小于等于 \(50\) 次。
[AGC072D] Magician
交互题。给定整数 \(N\)。有 \(N\) 种字母,你需要给每个有 \(N\) 个 \(0\)、\(N\) 个 \(1\) 的 01 串赋一个字母。有若干次询问,每次询问会先给定一个目标字母 \(c\),再给出 \(N\) 个位置对 \(a_i,b_i\),保证 \([1,2N]\) 每个位置出现且仅在一个位置对中出现。你有一个初始全 0 串,每次需要在 \(a_i,b_i\) 中选一个位置染成 \(1\)。每次染了上一个位置对后才会给下一个。最终需要让得到的字符串所赋的字母为目标字母。
\(2 \le N \le 10\)。\(1 \le T \le 5000\)。
CF1687E Become Big For Me
给定 \(n\) 和长度为 \(n\) 的序列 \(A\)。有一个初始为 \(1\) 的变量,你需要构造一个操作序列,每次操作可以选一个下标集合,然后选择将这个变量乘以或除以这个下标集合的 lcm。最终你需要让这个变量等于 \(\text{gcd}_{i \neq j}(a_i a_j)\)。
\(1 \le n \le 10^6\),操作次数需要小于等于 \(10^6\)。
QOJ 8130 Yet Another Balanced Coloring Problem
给定两棵大小分别为 \(n,m\) 的树 \(T,U\),满足这两个数分别以 \(n,m\) 为根,而且叶子节点编号均为一个区间 \([1,k]\)(\(k\) 没给)。现在你要给每个点赋一个 \(01\) 权值,满足两棵树的每个点的子树内两种类型的节点个数差绝对值小于等于 1,或报告无解。
\(3 \le n,m \le 10^5\)。

浙公网安备 33010602011771号