NOIP2024集训 Day44-45 略解

前言

不要谩骂以前的自己,他站在雾里也很迷茫。

题目比较多,整整 18 道,里面还有一道题我自己都不想写。

故本文可能会写的比较简略,主要是记录一下技巧方便自己复习和记忆。

反色刷

先看什么时候有解。

观察到你每次操作都是一条回路,黑色边要被操作奇数次。你可以考虑只看黑色边,考虑一个回路的性质,即每个点个这条回路相关的边的度数都是偶数,故你猜测每个点,与他相连的黑色边都是偶数条,那么他就是合法的。

稍微想一下可以发现这个显然是对的。

然后你去看操作次数。

实际上你对于一个连通块,只要其有黑边且有解,只需要操作一次,因为你操作多次,你可以通过无向图的性质将两个操作合并起来(即有些边你可以走出去再走回来,实际上是不会改变的)。

Code

丁香之路

有一个比较重要也比较麻烦的限制就是每条丁香路都必须被经过一次。

这个时候无论是最短路还是各种各样的什么连通性算法感觉都没什么帮助。

故你我考虑枚举终点,然后将起点和终点连在一起,这样就是求一条回路。(感觉这个东西是本题最重要的 Trick。)

由于是一条回路,所以这条回路上所有的点度数都是偶数。

考虑先将已经有的 m 条边和刚刚起点到终点的边连起来,由于是无向边,且这些点一定在最终的回路上,所以此时度数为奇数的点都要变成度数为偶数的点,且这样的点有偶数个。

显然,你要最优,一定是将这些奇数度的点按照编号排序,然后将相邻的两个两两连边,可以发现这样将奇数点变为偶数点,并且一定是最小的方案。(这个真的只能自己理解了,完全没空来详细证明)

在连完边之后,仍然可能会有多个连通块,此时每个连通块内部显然都存在欧拉回路。接下来的问题就是如何将两个连通块连在一起。

一个有趣的事实是,对于任意三个点 x,y,z,假设 x<y<z,他们之间的回路显然可以不经过 zx 这条边,因为你可以从 xy,yz,zy,yx,显然不劣于 xy,yz,zx

于是你走一个环,显然不如倒着走回去。

所以我们把连通块当作一个点,将两个点之间的边权定为这两个连通块之间最小的边权。

然后你跑最小生成树,记得答案要 ×2,因为你每条树边因为是回路要经过两边。

但是你直接暴力建图,因为还要枚举终点,复杂度就是 O(n3)

经过观察发现,对于一个联通块内部的任意一个点 x,我们找到距离他最近的(即相邻的如 x1,x+1 这种)点,且这个点不在这个连通块中,与这个点所在联通块连边,再跑最小生成树,复杂度 O(n2) 因为可以桶排。

这个正确性你可以通过 Boruvka 算法的过程来理解。

感觉上述的讲解比较感性,并没有太多的理论证明,但是感觉大致还是能懂的。

Code

骑士游戏

我们先考虑怪物互相之间构成一棵树的情况。

显然有一个树形 DP,定义 dpi 表示第 i 个怪物被杀死所需要的最少体力值,转移如下:

dpi=min(ki,si+j=1ridpVj)

观察到只有当 dpvj<dpi 时,第二种转移才有可能有效。

故我们考虑类似 Dijkstra 的算法,直接在里面转移就行了。

Code

雅加达的摩天楼

还算是比较不错的一道题。

发现这个 n,m 的范围是 3×104,非常的奇怪,所以一定是再告诉我们用一些奇奇怪怪的手段过掉。

考虑一个事情,对于所有的狗,他显然只能跳到 bi+k×pi,k\Z

发现跟模很相关,故引导我们走向根号分治。

在根号分治之前,有一个爆搜,就是说你搜索所有狗,在队列中插入收到消息的狗的位置,跳跃能力以及当前步数。

状态数显然是 O(n2) 的,因为在广搜的情况下,每个位置每种能力只有被搜到的第一次才是有用的。

观察到 pi>n 时,对于这些狗,所有他们所对应搜索的状态是 O(m×n) 级别的。

pin 时,对于这些狗,他们对应的有用的状态显然是 O(n×n)

所以其实你认为的 n2,有用的其实只是根号级别。

也就是说你只需搜索的时候每次都在有用的状态上就行了,可能要稍稍注意一下实现。

Code

奥运公交

首先不翻转是非常好求的,直接在原图上求出 1n,n1 的最短路即可。

然后对于翻转显然有一个 O(m2logn) 的暴力。

观察到 n 比较小,引导我们走向只对于翻转之后会产生较大改变的边进行重新建图跑最短路。

为了方便后面的求解,我们在正图和反图上,跑 1,n 的最短路数组(下面的 0/1 分别表示在正图和反图),然后我们枚举要翻转的边(假设是 (uv),边权是 w,反转代价是 c,对其进行分讨:

  • 如果他不在 1n,n1 的最短路上,你考虑对于 1n 的最短路,显然是 min(dis0,1n,dis0,1v+dis1,nu+w),对于 n1 的最短路,同理。然后加起来,再加上 c,对答案取 min 即可。
  • 如果他在最短路上,那么直接把这条边翻转,然后重新建图。(尤其注意如果你打的邻接矩阵,不能直接翻转。因为可能有重边。)然后再跑最短路即可。记得还原。

由于最短路不存在环,所以上面最多只有 n 个点,故总复杂度 O(n×mlogn)

Code

逛公园

观察到 k 比较小,但是边权有比较大,故你考虑先把每个点的最短路求出来,然后定义如下状态:

dpu,k 表示从 1u,路径长度为 du+k 的方案总数,其中 d 是最短路。

在草稿纸上稍微写一下得到转移式:dpu,k=dpv,dudv+kw(u,v)

最终答案即 i=0kdpn,k

转移你可以考虑一个记忆化,如果遇到了 0 环导致了记忆化到了自己,那显然答案是无穷个,直接输出就行了,否则正常记忆化是不会有后效性的。

Code

旅行者

题意清晰明了,即输出 k 个点中两两最短路的最小值。

直接建反图,用正图反图跑两遍多源最短路,并且记录当前这个点的最短路是到哪个起点的。

然后你枚举一个中间边,如果他在正图反图中对应的起点不同,就直接将两个图的最短路加起来再加边权对答案取 min

可以发现这样显然是对的,因为你在最优解中总能找到一条边满足一个断点和另一个端点对应的最短路起点不一样,这里不细证了,

Code

portal

其实是很聪慧的一道题。

对于每一个点,向上下左右连边,然后再向上下左右最近的能建传送门的地方和传送门的出口连边,你可以认为就是你在这个点发射,然后走过去。

正确性感觉显然(?

所以边数是 O(n×m) 级别,建完之后直接跑 Dijkstra 即可。

Code

The Wall

首先有一个重要的性质:最优筑墙方案一定包含最左上角的点到每个方格的左上角的点的最短路。

证明是比较简单的,如果没有包含,你把它包含进去,即向外部延伸显然不劣。(洛谷题解区其实有很多不错的图来理解)

又因为所有最短路构成了一棵最短路树,所以我们只要满足筑墙方案不穿过最短路即可。考虑把每一个点再拆成四个小点(一个方格对应 16 个点),在原图基础上再在相邻的、不穿过任意一条最短路树的边两点之间连一条边权为 0 的边,跑最短路即可。

比较难实现,这里只记录思想,所以代码咕咕咕了。

治疗计划

你考虑画一个图,然后你可以发现,对于两个治疗方案,如果 rilj+1|titj|(本质上就是会不会扩展到这个方案,可以看作一条斜率为 1,1 的线能不能连到另外一个治疗方案),那么我们将这两个治疗方案连边,然后跑一个点权最短路,就可以得到最终答案(起点就是 li=1,终点就是 ri=n)。

你发现貌似你无论怎么排序都不太好直接用 DS 优化建图啊。

然后有一个很逆天的东西,就是你在点权 Dijkstra 里面,每个点只会被松弛一次(类比一下,你在边权最短路里面显然也只会每条边松弛一次)

故你考虑打一颗势能线段树,然后只要一个点被松弛了就赋一个极值,每次只松弛在范围之内没有被松弛的从而保证复杂度。

Code

最小圈

古老的分数规划,直接二分答案,然后找环即可。

Code

糖果

你直接按照关系模拟,每次将其设为符合条件的极值,模拟 500 次你就过了,因为数据很水。

当然正解是差分约束,由于环的存在,需要缩点,然后跑拓扑即可。

Code

Nastia Plays with a Tree

额,感觉是比较简单的树形 DP

定义 dpx,0/1 表示将 x 的子树操作为一条链,x 是否是链的端点的最小操作次数。

转移感觉有手就行。

这个输出方案是非常恶心的,非常难搞,这里也懒得写,反正大家都会。

Code

Directed Tree

看到这种不合法,你是如何忍住不容斥的呢~

定义 dpx,i 表示 x 的子树内,有 i 个位置不合法的方案数。(不合法显然就是 i 这个位置填了 i 子树里面的)

显然有一个树上背包的转移,复杂度 O(n2)。然后你在算一下当前这个点不合法的贡献即可。

答案即 i=0ndp1,i×(ni)!×(1)i

Code

Logical Operations on Tree

显然,最终的顺序中,先 ANDOR 是最优的。

转化一下就是将 OR 的边删掉,剩下的连通块中,存在至少一个联通块里面的点权都是 1

然后容斥一下,就是没有,接着就是非常简单的树形 DP 这里不写了。

Code

Svjetlo

定义 dpi,0/1,0/1/2 表示,i 的子树里面灯泡都亮(除开他自己),i 是否亮,0/1/2 分别表示这个序列的起始位置和末位置有几个在 i 的子树里面。

转移依托答辩。

更详细的讲解见

Code

Black, White and Grey Tree

先考虑链的情况,假设这个链没有灰色,你考虑将一段相同的黑色或者白色合并在一起,那么这条链就变成了黑白相间的,假设长度是 len,你可以发现这条链的操作下限是 len2+1

感觉是比较好理解的。

然后考虑迁移到一棵树上。如果这棵树只有黑白,那么显然就是这棵树对应的链就是在黑白相同合并之后的直径。

而你现在就是要将灰色染成黑白然后求合并之后的直径的最小值。

考虑 DP,类似求树的直径,设 dpx,0/1 表示 x 染成白/黑,子树中某个点离它最大的距离,fx,0/1 表示 染成 x 白/黑 经过 x 的直径答案。

类似直径的转移。比较容易。

答案就是 max(min(fx,0/1))

Code

Fox And Travelling

首先,在环中的点一定不会被遍历。

用类似拓扑排序的过程可以把环上的点全部扔掉,剩下的点会构成若干个有根树和无根树,其中有根树的根是树中唯一与环中的点相连的点。

显然对于有根树,直接跑树上背包。

对于无根树,以树中每个点为根做一次有根树的树上背包,这样会发现每种选择 i 个点的方案会被多算 si 次,其中 s 为这棵无根树的大小,那么除掉即可。

然后合并即可。

Code

后记

18 道题,要累死了,救救孩子。

posted @   Saltyfish6  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
Document
点击右上角即可分享
微信分享提示