十一月、某、雪降る

十一月、某、雪降る

2uk6475k

USACO 部分题目解析

P8271 [USACO22OPEN] COW Operations S

手推性质,可以发现:题中给的两个操作,恰好等价于:字符串中的任意元素可以互相交换。这个很难发现,但是非常有用,启示我们要勤推性质。

所以我们将原字符串中的所有同类字符聚到一块,然后两两消去,最后每种字符必定剩下一个或者不剩。如果仅剩下一个 C,或者仅剩下一个 W 和一个 O,那么合法,否则都不合法。

至于 \(l\)\(r\) 的问题,我们可以用前缀和维护到 \(i\) 点截止,各种字符的总个数,然后实现 \(O(1)\) 查询。

P9977 [USACO23DEC] Bovine Acrobatics S

(待补全)

P10277 [USACO24OPEN] Bessie's Interview S

第一问可以开一个小根堆,然后往这个堆里依次扔所有奶牛的结束时间。事实上,这需要一个分类讨论:对于前 \(k\) 头奶牛,其结束时间就是它的 t 值;对于第 \(k+1\) ~ \(n\) 头奶牛,其结束时间是堆顶元素值加上它的 \(t\) 值。

然后考虑第二问。因为 Bessie 的开始时间就是奶牛的结束时间,所以首先我们枚举所有合法的结束时间,然后对于这个结束时间,将与它对应的开始时间作为新一轮的结束时间再次寻找,最终找到一个下标范围在 \(1\) ~ \(k\) 内的奶牛,你就赢了,把它的 \(ans\) 位记为 \(1\) 即可。我们可以用一个 set 来实现对这些时间的存储,顺便自动去重。

P9126 [USACO23FEB] Moo Route II S

题目说,对于一条航线,它规定它在时间 \(r\) 起飞,在时间 \(s\) 到达。所以不管你什么时候上飞机,到达的时间总是 \(s\) 这一个数。进而你可以把时间理解为一个变化的值,随且仅随边的 \(s\) 值而变化。

因为在 \(1\) 点的起始时间为 \(0\),所以不管 \(a_1\) 是什么,都要把它重设为 \(0\)

我们按 \(r\) 时间降序、\(s\) 升序排序所有边,这样在 SPFA 中可以提前终止无效搜索,即:如果当前航班的开始登机时间 < 到达时间 + 停留时间,由于航班按 \(r\) 时间降序排列,导致后续航班的 \(r\) 时间更小,都不满足条件。

对于一个边而言,它如果已经对它所指向的点产生了改变其 \(dis\) 值的作用,那么为了统计出最早的到达时间,它只需要产生这一次作用就可以了,不需要再被走第二次了。注意到循环里每次都要重复检查所有航班,即使大部分已经确定无效。所以我们可以使用一个记忆化存储,只检查可能有效的航班,用于记住上次检查到哪里,进而避免对已知无效航班的重复判断。

P6146 [USACO20FEB] Help Yourself G

自助者天助。——《易》

注意到数据范围 \(1\text{e}5\),所以肯定不能枚举所有线段子集。

考虑把贡献堆到线段上。定义 \(f_i\) 表示前 \(i\) 条线段对答案的贡献。

对于第 \(i\) 条线段,有选或不选两种选择:

  1. 选,那么贡献会多加上 \(2^k\),其中 \(k\) 是与第 \(i\) 条线段无交集的线段个数;

  2. 不选,贡献不变。

至于 \(k\),我们可以用前缀和预处理:线段 \(i\) 与$ \(j 无交集(\)i$ 在 \(j\) 的左边),当且仅当 \(i\) 的右端点严格小于 \(j\) 的左端点。这样的话,我们可以按照左端点对所有线段进行排序,然后计数。

综上,状态转移方程是 \(f_{i} = f_{i-1} + f_{i-1} + 2^k = 2f_{i-1} + 2^{s_{a_i.\text{left}-1}}\),其中 \(s_{\text{pos}}\) 表示小于或等于左端点 \(\text{pos}\) 的线段个数。

请记住,带有幂运算的取模,必须用快速幂。

P7991 [USACO21DEC] Connecting Two Barns S

因为我们最多造两条路,所以只有以下几种情况:

  • 不用造任何路,节点 \(1\)\(n\) 本来就是联通的;

  • 节点 \(1\) 所属的连通分量与节点 \(n\) 所属的连通分量是两个独立的连通分量。

    • \(1\)\(n\) 所属的连通分量中找出差值最小的两个点连边;

    • \(1\)\(n\) 所属的连通分量跟第三个连通分量相连。

定义 \(f_i\)\(g_i\) 分别表示节点 \(i\)\(1\)\(n\) 所在的连通分量相连的最小开销。

可以先求出与 \(1\)\(n\) 在同一连通分量的点集,使用并查集维护,再开一个表记录这些点的编号。

然后对于每个点 \(i\),在这两个表里二分,找到与其差值最小的点,然后更新 \(f\)\(g\) 的值。

答案为 \(\min(f_i+g_i)\)

P7411 [USACO21FEB] Comfortable Cows S

(待完善)

P7301 [USACO21JAN] Spaced Out S

造几组样例可以发现,要想使得所有 \(2×2\) 的子矩阵有且仅有两个 C,必须要么使得每行的 C 交替放置,要么使得列与列之间的 C 交替放置。这里的交替放置是指,C. 一个隔一个地放置。而且相邻两列或行之间的交替放置方式没有影响。所以我们分别模拟两种放置方式,取交替放置某一列或行奇数位和偶数位的最大值,统计两种放置方式的最大值即可。

P7299 [USACO21JAN] Dance Mooves S

手模样例,发现同一个点在不同循环节中经过的点是相同的,只是他们的顺序发生了改变。

我们把这样的一组点称作一个连通分量,于是使用并查集找出这样的连通分量,同一连通分量内的位置可以互相到达。

P8186 [USACO22FEB] Redistributing Gifts S

对于一个奶牛,他最开始被分到了自己编号的物品。所以,为了获得更好的物品,他想要将自己的物品与“在他愿望清单中比自己物品价值高”的物品互相交换。

这样的交换关系非常多,而且我们发现,交换关系还具有传递性,那么我们可以想到图论建模。对于每个编号为 \(i\) 的牛,对于他愿望清单中,比 \(i\) 靠前(包含 \(i\))的礼物 \(a_{i,j}\),建一条单向边,表示 \(i\) 想要与 \(a_{i,j}\) 交换物品(但反过来不一定)。

这样建完图之后,如果两个节点能够互相到达,证明这两个节点都能使得互相的物品分配方案最优化,进而证明他们可以互相交换物品。所以,我们跑传递闭包即可。

如果这两个节点有多个物品可供交换,就选择最靠前的那个即可。

P6005 [USACO20JAN] Time is Mooney G

图上 DP。定义 \(f_{i,j}\) 表示第 \(i\) 天到达城市 \(j\) 能赚到的最多的钱。

首先我们忽略消极贡献,根据题意,\(f_{i,j}=\max(f_{i-1,\text{fa}(j)}+w_j)\),其中 \(\text{fa}(j)\) 表示指向 \(j\) 的节点。所以我们可以构造反向边,便于找到 \(j\) 的邻居节点来进行转移。

我们需要的答案即是 \(\max(f_{i,1}-ci^2)\)

P8266 [USACO22OPEN] Photoshoot B

本题的题意是这样的:给你一个仅由 G 和 H 构成的串,你可以选择一个 \([1,2i]\) 的子串进行翻转。想要让这个字串所有处于偶数位的 G 的个数尽可能多,求最少的反转次数。

首先这道题的样例很水,可以自己造几个,然后写一个爆搜找规律(如果时间充足)。

我们发现,对于一对相邻的字符(前一个是奇数位,后一个是偶数位),它们被反转后不会有任何效果当且仅当这两个字符相同。如果他们反转后有效果,那么会产生两种效果:

  1. 积极效果,即 GH,反转后变为 HG,增加一个处于偶数位的 G;
  2. 消极效果,即 HG,反转后变为 GH,减少一个处于偶数位的 G。

所以,我们两个两个地遍历这个字符串,如果两字符相同,不予记录;如果是 GH,那么证明增加这个偶数位的 G 需要添加一次反转;如果是 HG,那么证明不需要反转。

遍历这个 0-1 串,记录连通块的数量即可。

洛谷 2025 NOIP 模拟赛

T1 P14507 缺零分治 mexdnc

(待补全)

T2 P14508 猜数游戏 guess

场上看到这道题直接蒙了,什么是最优策略和最坏情况?后来才搞明白。首先你需要弄明白这道题的题意。

关于“最坏情况”:因为题里说,可以根据询问的结果来决定策略,所以系统在每次移动策略改变的时候,都会使得根据玩家目前的移动策略来说,移动最多的步数,才能查明棋子的位置。这里的“查明”是指弄清区间内棋子的具体位置。

关于“最优策略”:在满足“最坏情况”的棋子位置限制时,移动策略的最小花费。

我们考虑,要想知道棋子处于哪个位置,必须查明棋子所属区间(即 \([1,n]\))内的每一格都是否有棋子。进一步地,对于某一区间,从左端点开始走,想要查明这个区间内每个格子的状态,你所需要的最小花费,与区间端点的索引完全无关。这是因为,题目内只有一个区间,而这个区间的索引是固定且唯一的,所以棋子的存在范围是固定的。因此,对于任意的区间,使得它的长度与题中所给区间的长度相等,这个区间内的棋子分布规律也是固定且唯一的,都和题中所给区间的分布规律一致。

所以,最小开销仅与区间长度有关。定义 \(f_i\) 表示在最坏情况下,查明长度为 \(i\) 的区间所需的最小花费。

根据一般的策略来说,我们一直往棋盘的正方向走,如果了解到某一区域内有棋子,就往反方向走。于是对于一个长度为 \(i\) 的区间,我们从它的左端点开始走。

假定我们走了一个长度为 \(j\)\(j<i\))的区间,那么我们获取到的信息就是这个长度为 \(j\) 的区间内是否存在棋子。进而,我们分情况讨论:

  1. 如果这个区域内不存在棋子,我们就需要再去查明前面长度为 \(i-j\) 的区间是否有棋子,其花费为 \(f_{i-j}\)

  2. 如果这个区域内存在棋子,那么说明那个长度为 \(i-j\) 的区间内肯定没有棋子,这就使得我们需要往回走,也就是查明长度为 \(j\) 的那个区间内的棋子情况,花费为 \(f_j\)

因为我们考虑的是最坏情况下的最优解,所以对这两种情况取最大值。

不妨设走过(而并非查明)长度为 \(j\) 的区间的最小开销为 \(\text{dis}_j\),那么总的状态转移方程就是

\[f_i=\min(f_i,\text{dis}_j+\max(f_{i-j},f_{j})) \]

接下来我们只剩一个问题,就是 \(\text{dis}\) 的求法。我们知道,不同移动方式移动的格数和代价都有所不同,所以我们考虑构造一条链,每一种移动方式对应着一条连接往左走和往右走的边,其边权为 \(b_i\)。然后跑 Dijkstra 即可。

最后答案为 \(f_n\)

关于组合数学

P1287 盒子与球

如果忽略没有空的条件,答案显然是 \(r^n\)。但如果我们考虑上这个条件呢?

现在考虑一种放法,使得该方法内,至少\(k\) 个空盒子。

\(r\) 个盒子内,选出 \(k\) 个盒子,使它们一定为空,显然有 \(\tbinom{r}{k}\) 中选法。所以,现在还剩下 \(r-k\)可不空也可空,即忽略限制的盒子。

对于那 \(n\) 个球,放入 \(r-k\) 个盒子,每个球都有 \(r-k\) 种放法,那么这 \(n\) 个球放入这 \(r-k\) 个盒子中的总方案就是 \((r-k)^n\)

刚才叙述的两个方面是解决同一问题的两个步骤,故使用乘法,因此得到:某种放法内,至少有 \(k\) 个空盒子的总方案数为 \(\tbinom{r}{k}(r-k)^n\)

因为这里考虑的是至少,所以它表示的是方案集合的并。要用并求交,就可以用容斥原理的变式。

P3197 [HNOI2008] 越狱

可以算出总的情况,然后减去信仰宗教不同的情况。

总的情况就是每一个人可能信仰 \(m\) 种宗教,显然总的情况数就是 \(n^m\)

至于不同的情况,我们可以这么考虑:如果第一个人有 \(m\) 种选择方式,第二个人为了不跟他重复,只有 \(m-1\) 种选择方式,第三个人为了不跟第二个人重复,也只有 \(m-1\) 种选择方式……总之,如果所有相邻的人信仰的宗教都不相同的情况有 \(m(m-1)^{n-1}\) 种。

所以,答案就是

\[m^n-m(m-1)^{n-1} \]

P4071 [SDOI2016] 排列计数

P1595 信封问题 很像,都是错排问题,但这道题要求取模,所以我们想到了逆元。注意逆元板子咋写。

P5520 [yLOI2019] 青原樱

组合数问题,需要使用多种技巧求解。

因为上一步的树苗们已经占用了 \(m\) 个空位,所以现在还剩下 \(n-m\) 个空位。

因为任意两个树苗之间必须有空位,所以我们可以把剩下的 \(n-m\) 个空位看作物品,把树苗看作隔板,进行隔板法计算。

这样做的原因是,因为多个隔板不能放在同一个位置,所以将树苗看作隔板这一操作,确保了相邻两树苗之间必定至少有一个空位。

于是 \(n-m\) 个空位这些物品中,供隔板放置的空位就有 \(n-m+1\) 个,要把上面的 \(m\) 个树苗放在这些空位里。

因为树苗是有编号的,所以这里使用排列数计算,即 \(A_{n-m+1}^m\)。输出这个值即可,记得取模。

P2638 安全系统

分别考虑 \(0\)\(1\) 的放置方案,然后相乘即可。

考虑隔板法,这里允许袋子为空,所以添加 \(n\) 个虚拟物品,然后跑隔板法,相当于在 \(n+a+1\) 个物品中,即 \(n+a\) 个间隔中,插入 \(n\) 个隔板,即 \(C_{a+n}^n\)

关于 MST

P1195 口袋的天空

先跑 Kruskal,由于该算法基于贪心,所以每次寻找的都是最小的边。当边数等于 \(n-k\) 时,则说明边数等于 \(n-k\) 的生成树已构建,已形成 \(k\) 个连通块,此时输出目前的 \(ans\) 即可。如果整个 Kruskal 跑完都没能使边数达到 \(n-k\),说明不合法。

P1550 [USACO08OCT] Watering Hole G

可以搞一个超级源点 \(0\),对于任意点 \(i\) 和它连边的边权都是 \(w_i\),然后带着这个超级源点跑 Kruskal。

P2573 [SCOI2012] 滑雪

题意:从点 \(1\) 出发构建一棵 MST,但保证点权较大的点始终指向点权较小的点,求该 MST 中最多的点数及其大小。

因此,我们只能从点权较大的点往点权较小的点建单向边。

因为时间胶囊的存在,我们可以无限次回溯,所以只需要从点 \(1\) 根据上面的建边规则进行 BFS,然后统计搜到的点的个数,即为第一问的答案。

为了使得在生成树最小的同时使能到达的景点数最多,我们需要以点权为第一关键字排序,使得点权较大的尽量排在前面,便于为以后点权较小的点留出空间;再以边权为第二关键字排序;最后跑 Kruskal 即可。

P2700 逐个击破

题意:给你一个有权树,上面的某些点会有标记,现在让你断掉若干个边,把这个树分成若干个连通块,使得每个连通块里包含且仅包含一个有标记的点。求被断的所有边的边权和的最小值。

注意到,断边的边权和最小值,就是保留边的边权和最大值。

所以我们使用加边法跑这棵树(即 Kruskal 算法)。

值得注意的是,我们在将所有边排序的过程中,必须将所有边从大到小排序,这样才能确保所保留边的边权和达到最大。

在遍历所有边的时候,如果该边连接的两个点均有标记,那么不能将其累加到答案贡献中。因为如果将其累加,就证明这个操作必定会将两个有标记的点放到一个连通块里,这是非法的。

另外,如果该边连接的两个点中,有且仅有一个点有标记,或者是两个点都没有标记,那么就能将其累加到贡献中。特别地,如果满足“有且仅有一个点有标记”,那么需要将两个点策略性地都打上标记,以确保该连通块里有且仅有一个点有标记。

P1265 公路修建

题意:给你直角坐标系上的若干整点,让你求这些整点构成的最小生成树。

因为任意的整点之间都能连边,所以这些点构成的图一定很稠密。如果枚举边,按照 Kruskal 跑最小生成树的话,肯定会超时,所以我们采用 Prim 算法。

Prim 算法的主旨是“加点”,也就是说,将你所枚举的点的连边加入最小生成树中。因为这张图会有很多边,而且这些边的预处理需要极高的时间复杂度,因此我们可以使用朴素的 Prim 算法,在枚举点的时候,直接把这个点的所有连边现场计算出来,选最小的即可。到头来,这道题还是 Prim 板子。

posted @ 2025-11-28 18:42  L-Coding  阅读(8)  评论(0)    收藏  举报