NOI 真题记录

NOI2024

P10785 [NOI2024] 集合

很牛的一道哈希题。不过感觉随便试一试就能猜出结论,不太难。

首先尝试刻画一个条件来判定合法,经过我们手玩+尝试/从集合大小为 \(1\) 开始思考并推广,之后可以发现条件是 \(a\)\(b\)\([l,r]\) 内每个数的出现位置的小集合组成的大集合相等。

我们不太方便用一个数据结构来一次查询 \([l,r]\) 的哈希值,于是考虑莫队。但是我们要设计出一个可以支持动态加减的元素的哈希,如果采用常规的 \(P\) 进制其实不太好刻画无序集合&动态删改元素之后的顺序性。需要用一个具有快速可逆性的运算,可以用 "和" 哈希。

\[H(l,r)=\sum\limits_{\exists i\in[l,r],x_\in a_i}G(F(set_{x})) \]

对于 \(F\) 是一个集合哈希,可以对于每个位置下标都赋一个随机数,然后 \(F\) 就是把集合内的的数异或起来,\(G\) 是再把这个数变化一下,一般常用多项式结合位运算随便搞一个就行了。这样是时间复杂度是莫队的 \(O(n\sqrt q)\) 的。这样子能获得 \(90 \rm pts\)

可以发现位置越多其实是增加的限制越多,所以这个区间应该是满足双指针性质的,使用双指针即可做到线性。哈希部分可以多做几次提高正确性。

P10786 [NOI2024] 百万富翁

单组就是 \(O(n^2)\) 次询问。

现在考虑可以询问多次,可以很容易设计出一个经典淘汰赛式线段树结构出来,但是缺点是一共会有 \(\log n\) 层,因此询问轮数会很多。思考有哪些浪费轮数的行为,我们发现线段树结构单层的询问次数会急剧下降。最后几轮都是对于极少的几个元素进行操作,极其不划算。

考虑将单组询问的做法拿过来,对于元素个数少的时候我们直接进行暴力,一轮结束,就可以大大缩短轮次。我们寻找一个阈值满足剩余的询问次数可以对于当前所有元素进行暴力的时候直接进行暴力两两询问,这样子大概能拿到 \(52 \rm pts\)

发现此时的瓶颈还是轮数,考虑将这个做法扩展一下,我们不一定是要对着全局进行暴力两两询问,可以分组之后进行暴力询问。

关于分组策略可以直接暴搜,注意到前四组必然是 \(2\) 个一组,固定之后,对于后续搜索一下,可以得到序列 2,2,2,2,3,6,19,183。根据这个来写,可以得到 \(82 \rm pts\),现在轮数合法了,但是总操作次数还是。最优的方案还需要微调,可以手动进行一下,前 \(4\) 轮都恰好能整除肯定是最优的。第 \(5\) 轮剩余元素个数 \(\bmod 3 =1\),根据 \(x^2\) 的凸性,\(3+1\) 分组肯定是不如 \(2+2\) 分组的,于是调整一下。按照这个方法继续往下算即可,每次调整成均匀的。

下面介绍精细构造方案的通法,dp。

我们设 \(dp_{i,j}\) 表示剩余 \(i\) 次询问有 \(j\) 个人的最小代价。

\[dp_{i,j}=\min\limits_{k}(dp_{i-1,k}+\rm cost(j,k)) \]

其中 \(\rm cost(j,k)\) 表示把 \(j\) 个人分成 \(k\) 组的最小代价。可以发现根据均匀分的策略,会有 \(j\bmod k\)\(\lfloor\dfrac{j}{k}\rfloor+1\),有 \(k-j\bmod k\)\(\lfloor\dfrac{j}{k}\rfloor\),可以 \(O(1)\) 计算代价。暴力转移是 \(O(tn^2)\) 的,把前四次除以 \(2\) 的步骤固定下来,跑这个暴力其实还是挺快的。

注意到这是一个整除分块的结构,只有 \(O(\sqrt n)\) 种不同的 \(\lfloor\dfrac{j}{k}\rfloor\),在同一取值区间 \([l_i,r_i]\) 内决策一下,可以发现当 \(k\) 越小的时候组数少,如果此时 \(+1\) 的个数也更少就代表肯定更优,所以当 \(x\mid j\) 的时候,所有 \(>x\) 且和 \(x\) 在同一取值区间内的数肯定是不优的,当然使得 \(j\bmod k\) 小的数可能不一定是整数,所以应该是在 \([r_{i-1},l_i]\) 之内取到的,所以我们直接取所有 \(l,r\) 进行决策即可。可以把时间复杂度降到 \(O(Tn\sqrt n)\)

P10787 [NOI2024] 树的定向

\(\rm subA\) 都会做了,为什么想不出来 \(\rm poly(nm)\) 的做法呢??好好反思。

对于 \(\rm subA\),考虑限制最严的地方,就是那些距离为 \(2\) 的点,所以我们需要对于相邻两条边方向定向为相反方向。直接对于树上的点进行二分图染色即可,给每条边定向黑 \(\to\) 白。

字典序最小肯定是逐条边确定,现在需要判定给这条边赋 \(0\) 之后是否会让某些限制不满足,直接去做这件事是很难做的,因为你不枚举剩余边的定向情况很难综合考量这个事情,你无法直接判定剩下路径有没有一些限制的相互作用。

此时不妨直接大胆猜测,只要每条路径 \((u,v)\) 上有至少两条边没有被定向,那么必然有解,且此时我们任意给某条边定向之后依然有解。 为什么这个是对的呢?考虑 \(\rm subA\),我们在任意距离为 \(2\) 的点都要求不连通这个最严的条件下都能有解,其他情况必然有解。

于是我们逐条边考虑,将已经满足的路径限制删除,寻找剩余路径中仅有一条边未被定向的路径给那条边定向,然后如果当前边还未被定向,就给当前边定向。时间复杂度 \(O(nm\log n)\)

发现瓶颈在于寻找还有一条边未被定向的路径,考虑一个类拓扑排序的过程,我们将一条路径和其上的所有点进行连边,这一步可以采用树上倍增优化建图,拓扑排序的时候将点加入队列的判定条件是入度 \(\le 1\),代表着其路径上未定向的边数量已经不足两条,可能可以确定唯一一条边的方向。

然后从小到大枚举所有边,先把队列中的路径都拿出来,把需要定向的边都给定向了,注意这一步我们首先需要判定这个路径是否已经不连通,如果依然联通,我们需要找到唯一一条未定向边进行反向定向。这两步都可以用树上并查集实现,每确定一条边,我们就把其两个端点相连,这样子可以快速寻找到某条路径上未定向的边,同时我们维护一个树上前缀和(并查集 find 操作的时候维护),代表向下边的数量,和每个点的深度,通过深度和向下边的数量前缀和可以快速得到某条祖孙链上的向上和向下边的数量。

把所有必须定向的边都定向过后,如果目前枚举到的边依然没有被定向,那么就可以对其进行任意定向,根据字典序最优,我们将其设置为 \(0\)。每给一条边定向之后,我们都要从它出发进行一个拓扑排序,解锁其他的边/路径。

时间复杂度 \(O(n\log n)\)

P10788 [NOI2024] 分数

如果按照题目中给的构造方式搜索就输了,由于要记忆化,所以超过 \(70 \rm pts\) 的部分会直接 MLE,毫无任何优化空间,难以继续。

题目中是一个一个搜,考虑从某个分数开始一下子搜索很多数。

NOI 2023

NOI2022

P8501 [NOI2022] 二次整数规划问题

首先,约束条件可能和固有上下界产生冲突,导致区间内有些数不可能被取到,我们直接类似于 SPFA 跑 \(n\) 轮松弛一下这些约束就行了,这样子每个数在取值区间内的数都可能被取到。然后固定一些 \(l_i=r_i\) 的数,还有一些数 \(l_i\neq r_i\),但是 \(1\in [l_i,r_i],5\in [l_i,r_i]\),这个时候就把 \(1,5\) 从值域中踢出去,原因会在下一段提及。

最大化的式子中可以发现,首先 \(v_1\)\(v_k\) 无贡献,其次取 \(1,k\) 的时候对于 \(G\) 的贡献没有那么优。所以通过调整法,我们可以发现选 \(1\) 或选 \(k\) 不如选 \([2,k-1]\)。除了那些必须选 \(1\)\(k\) 的位置外,值域可以缩小到 \([2,k-1]\)

对于部分分,\(k=3,4\) 都可以运用基础调整法迅速得到最优解的形式。对于 \(k=3\) 的时候,能选 \(2\) 就选 \(2\)。对于 \(k=4\) 的时候,贡献函数关于未知数为线性形式,所以那些未确定数要么全选 \(2\),要么全选 \(3\)

对于 \(k=5\) 的时候。建议再读一遍第一段的第一步变量取值处理,然后再看这段文字。未确定数的取值有 \(\{2,3,4\}\)。首先思考约束关系,那些必定取某个值也就是 \(l_i=r_i\) 的位置如果对于未确定数产生约束的时候肯定在松弛的时候已经产生过了。比较难限制的是动区间的约束,比如两个取值为 \([2,4]\)\([2,4]\) 的变量,要求距离 \(\le 1\),也就是不能一个 \(2\),另一个 \(4\),在松弛那一步约束不到这里。可以发现在 \(\{2,3,4\}\) 集合内,约束为 \(1\) 的条件传递两次没有意义,因为传递两次之后就变成了距离约束为 \(2\),而集合内部的最大距离也就是 \(2\),所以没有用了。但是距离为 \(0\) 的约束传递多次还是紧的,可以用并查集处理。

于是,总结一下变量取值范围的约束大部分在松弛那一步已经处理完了,还有两个需要处理,一个是两个变量要求距离 \(\le 1\)(这个两个变量只可能是 \(m\) 条约束中的某个),还有一个是一些变量要求相等 (不一定为 \(m\) 条约束之一,可能是通过并查集传递的)。

处理完变量取值范围之后,我们回到最优化问题上来。可以发现贡献函数形式必定如下所示,其中 \(V_i=v_i+?\),这个 \(?\) 代表一些距离大于 \(1\) 的变量贡献需要扣掉,反正是关于未知数是一个线性关系。

\[W=10^6(n^2-2c_2c_4)+\sum\limits_{i=2}^4c_iV_i+\lambda \]

化简式子,就是就是形如 \(-M(c_2-A_1)(c_4-A_2)+A_3\)

\((c_2,c_4)\to (x,y)\),我们需要最小化 \((x-A_1)(y-A_4)\)

其中可以发现目前已知三个点肯定能取到,分别是 \((x_{\min},y_{\min})\)\((x_{\min},y_{\max})\)\((x_{\max},y_{\min})\)\(x_{\min}\) 就是只有那些松弛过后 \(l_i=r_i\) 的点产生贡献,\(x_{\max}\) 则是把所有 \(2\in[l_i,r_i]\) 的点都压到了 \(2\),保证能取到是因为这些动区间点聚集在一起之后距离肯定为 \(0\) 也就肯定满足约束,而剩下点还是那一句话定点对于动区间点的约束已经在松弛一步约束过了,所以这三个点肯定能取到。

我们现在需要处理出一个可能取到最优答案的点集,遇到哪个询问,就直接对于点集内所有点代入算一遍看看哪个最优就行了。你直接把所有可能的合法点放入这个点集,显然复杂度是要爆的。因此我们需要挑出一些有用的点放入,一些 \(100\%\) 不可能产生贡献的点就不放进去了。

题目要处理的就是平移之后的 \(x'y'\) 乘积最小值。可以发现如果平移之后,还存在点处于 \(1,2,4\) 象限,那么肯定包含上面三个定点之一,选择它们是最好的(这个可以自己画画图就能看出来)。因此先把这三个点纳入点集。

问题是如果所有点都被移动到了第三象限怎么办?乘法之后负负得正,我们可以作出判断,只有上凸壳上面的点是有效的(注意如果是 \(x,y>0\) 那么是下凸壳,但是这里 \(x,y<0\),所以是上凸壳)。

根据引理,

在一个 \(V\times V\) 的矩形上,凸包点的个数是 \(O(V^{\frac{2}{3}})\) 的。

于是我们就把有用点点集大小缩小到了凸包大小量级,也就是 \(O(V^{\frac{2}{3}})\)

可惜我们无法直接显式建立这个凸包。不过根据 P5540 的 trick,我们可以解决这个凸包问题。我们知道凸包上的两点 \(P(x_{\min},y_{\max})\)\(Q(x_{\max},y_{\min})\)。我们可以通过已有的两点去构建这个凸包,直接寻找所有点还是不容易,考虑哪个点是一定在凸包上的,那么就是一个点 \(R\) 满足在直线 \(PQ\) 上方且离 \(PQ\) 距离最大。找到 \(R\) 点之后更新答案,并且分治为 \((P,R)\)\((R,Q)\) 去解决问题,这样子我们每次找到一个肯定在凸包上的点,总的寻找复杂度也就是凸包上点的个数乘以单次寻找时间复杂度。

现在考虑如何找到 \(R\) 点,上述条件等价于三角形 \(PQR\) 的面积最大,也就是 \(\vec{RP}\times \vec{RQ}\) 最大。代入坐标,利用叉乘公式计算之后可以得到,希望最大化 \((X_Q-X_P)y_R+(Y_P-Y_Q)x_R\),也就是最小化 \((X_P-X_Q)y_R+(Y_Q-Y_P)x_R\)

也就是说每个数如果选 \(2\) 就会有 \(Y_Q-Y_P\) 的代价,如果选 \(4\) 就会有 \(X_P-X_Q\) 的贡献,选 \(3\) 没有贡献,同时一些数之间会有在上文中的两个约束。这显然是一个切糕模型的形式。每次利用切糕模型建图,代价可能是负的,平移 \(n\) 即可。跑最小割即可。利用最小割的流量信息求出一组方案,然后找到凸壳上的点,继续分治就行了。注意找到点之后要验证其是否在凸包上,以防复杂度退化。

时间复杂度 \(O(n^{\frac{2}{3}}(q+\rm Dinic()))\)

NOI 2021

P7736 [NOI2021] 路径交点

对于 \(k=2\) 的时候,首先两两匹配可以看成排列。交点个数其实就是 \(p_i\) 排列逆序对数量,奇数 \(-1\),偶数 \(+1\),可以发现这个和行列式定义一样,于是直接对于邻接矩阵求一个行列式,也就是 \(\det(A)\)

对于 \(n_1=n_i\) 的时候,可以直接把求出相邻两列的行列式,然后再相乘,也就是 \(\prod \det(A)\)。因为偶数贡献 \(+1\),奇数贡献 \(-1\),两个奇数遇到就会变成偶数,其贡献也会变成 \((-1)\times (-1)=1\),因此上述按照贡献法是对的。

对于一般情况就不是排列了,也不是 \(n\times n\) 的矩阵了。其实很容易猜到就是先 \(\prod A\),将其变成 \(n\times n\) 的矩阵,然后再求 \(\det\)。至于证明的话,就是 \(\prod A\)\((i,j)\) 就是第一列的 \(i\to\) 最后一列的 \(j\) 的路径方案数。而且还自动满足了路径不能重合这个条件,因为重合路径的逆序对差为 \(1\),就抵消了。

P7738 [NOI2021] 量子通信

注意到 \(256=16^2\),直接划分成 \(16\) 份。

\(k_i\le 15\),根据抽屉原理一定有一个公共块,直接暴力寻找然后枚举判断即可。

其中单个块内期望个数是 \(\dfrac{n}{2^{16}}\)

NOI2020

P6776 [NOI2020] 超现实树

只需要判定一条无限长的链的存在性。

假设在右子树内,如果左子树为空的话直接递归,否则必须只有一个点,不然的话可以构造出一个左边多一个无法加的点,右边不断伸长的链,这样子就不合法了。于是我们把给的 \(m\) 颗树重新编号成为一种编号方式的树。然后遍历每个节点判定即可。

posted @ 2025-04-18 22:52  Mirasycle  阅读(149)  评论(5)    收藏  举报