今天是黄致焕老师的讲授~
历年真题选讲
NOIP 2012 开车旅行
小 A 和小 B 决定外出旅行,他们将想去的城市从 1 到 n 编号,且编号较小的城市在编号较大的城市的西边。记城市 i 的海拔高度为 Hi,城市 i 和城市 j 之间的距离 d ( i , j ) 恰好是这两个城市海拔高度之差的绝对值,即 d ( i , j ) = | Hi − Hj | 。
旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次 。他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。
现在给定两个问题:
对于一个给定的 X = X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小。如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。
对任意给定的 X = Xi 和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程总数。
数据范围
2 ≤ m ≤ n ≤ 50000
题解:
• 首先如何考虑对于每一个城市,小 A 和小 B 分别会走向哪一个后续城市。
• 考虑从后向前扫每一个城市,将 H 离散化,用一个权值线段树维护每一个 H 是否有对应该海拔的城市。
• 这样我们就可以在线段树上求出小 A 和小 B 分别会走向哪一个后续城市了。
• 考虑倍增。
• 用 fi,j 表示从点 i 开始走,小 A 先走,小 A 和小 B 分别走了 2j 步走到哪个点。
• 用 gi,j 表示从点 i 开始走,小 A 先走,小 A 和小 B 分别走了 2j 步,两人一共走了多少距离。
• 用 hi,j 表示从点 i 开始走,小 A 先走,小 A 和小 B 分别走了 2j 步,小 A 一共走了多少距离。
• 有了这三个值,我们就可以快速求出从某个点出发走最多 X 距离会走到哪个店,两人分别走了多少距离了。
• 对于第一种询问,我们可以枚举开始点,之后用倍增求出两人分别走的距离,求出比值,更新答案。
• 对于第二种询问,由于有确定的开始点,直接进行倍增即可求出两人分别走的距离。
时间复杂度 O ( n log n ),空间复杂度 O ( n log n ) 。
NOIP 2012 疫情控制
H 国有n个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。
H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
数据范围
2≤m≤n≤50000
题解:
• 首先思考如果我们已经确定了时间,如何判断是否可以控制疫情。
• 容易想到每个军队一定是尽量向根走比较好。
• 对于那些可以走到根的所有军队,分两种情况讨论
• 1、走到根之后还能继续走。这些军队我们可以分配给根的任意一个儿子。
• 2、走到根之后不能继续走了。这些军队我们让他退回走到根前的那个节点。
• 确定除了情况1的所有点后每个点的最终位置,我们通过 dp 求出根有多少个儿子需要建立检查点。
• 如果情况 1 中的军队足够分配给这些儿子,那就可行,否则不可行。
• 由于答案显然具有可二分性,所以我们只要二分答案即可。
• 时间复杂度 O ( n log n ),空间复杂度 O ( n ) 。
NOIP 2013 火柴排队
涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度。现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑ ( ai - bi )2。
其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对99999997 取模的结果。
数据范围:
1 ≤ n ≤ 100000
题解:
• 发现肯定要让 a 中第 k 大的和 b 中第 k 大的匹配才能最小化距离。
• 同时移动 a 和 b 与只移动一个没有区别,所以我们可以确定 a,只移动 b。
• 首先我们可以将 a 和 b 都离散化,用 Ai 表示 ai 是 a 数组中第几大的,用 Bi 表示 bi 是 b 数组中第几大的。之后定义数组 C 满足 CAi = i。
• 定义数组 D 满足 Di = CBi,表示 b 中第i项最终需要移动到哪一位。
• 发现移动步数相当于对D数组进行排序,只能移动相邻两项的最少步数。
• 等价于求逆序对数。
• 用归并排序或树状数组即可。
• 时间复杂度 O ( n log n ),空间复杂度 O ( n ) 。
NOIP 2013 华容道
在一个 n * m 棋盘上有 n * m 个格子,其中有且只有一个格子是空白的,其余 n * m - 1 个格子上每个格子上有一个棋子,每个棋子的大小都是 1 * 1 的。
有些棋子是固定的,有些棋子则是可以移动的 。
任何与空白的格子相邻的格子上的棋子都可以移动到空白格子上。
游戏的目的是把某个指定位置可以活动的棋子移动到目标位置,有 q 组询问。
问最少步数。
数据范围:
1 ≤ n , m ≤ 30 , q ≤ 500
题解:
• 通过思考,发现只有空白格子在目标棋子周围是关键状态。
• 我们可以用 fi,j,k 表示棋子在点 i , j,空白格子在棋子的 k 侧。其中 k = 0~3,分别表示 4 个方向。
• 转移分为两种:
• 1、棋子和空白格子交换位置。
• 2、棋子不动,空白格子通过和其他棋子交换走到棋子的另一侧。
• 第一种情况需要走一步,第二种情况可以用 gi,j,k,l 表示棋子在点 i , j ,空白格子从棋子的 k 侧走到l侧最少需要几步。
• 第二种情况的值可以对于每一个 i , j , k , l 进行预处理,预处理时只要跑一遍 bfs 求出最短路即可。
• 之后对于每一组询问,我们先求出空白格子移动到棋子的每一侧的最少步数,之后利用我们预处理出来的东西进行转移跑一遍 dijstra 即可。
• 时间复杂度 O ( n * m * log ( n * m ) * q ),空间复杂度 O ( n * m ) ;
NOIP 2013 货车运输
A 国有 n 座城市,编号从 1 到 n ,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制ai,简称限重。
现在有 q 辆货车在运输货物,第 i 辆车从城 xi 将货物运送到城市 yi ,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
数据范围:
0 < n < 10000,0 < m < 50000,0 < q < 30000
题解:
• 观察题目,经过思考,发现两个点之间最小值最大的路径一定在最大生成树上。
• 所以我们可以先用 Kruskal 算法求出最大生成树。
• 之后问题转化为链上最小值。
• 首先我们可以以 1 为根建树,之后用倍增算法。dadi,j 表示 i 的 2j 的父亲,maxi,j 表示 i 到他的 2j的父亲路径上所有边的最小权值。
• 这样我们在求 lca 的同时可以求出链上最小值。
• 时间复杂度 O ( m log m ),空间复杂度 O ( n log n ) 。
NOIP 2014 寻找道路
在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
1. 路径上的所有点的出边所指向的点都直接或间接与终点连通。
2. 在满足条件 1 的情况下使路径最短。
注意:图 G 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
数据范围:
0 < n ≤ 10000,0 < m ≤ 200000
题解:
首先我们可以将所有边反向,从终点开始进行一次 bfs,求出所有可以走到终点的点。
之后我们可以求出所有合法点,再从起点进行一次 bfs 求出最短路即可。
时间复杂度 O ( n ) ,空间复杂度 O ( n ) 。
NOIP 2014 飞扬的小鸟
游戏界面是一个长为 n,高为 m 的二维平面,其中有 k 个管道(忽略管道的宽度)。
小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
小鸟每个单位时间沿横坐标方向右移的距离为 1,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升 Xi,每个单位时间可以点击多次,效果叠加。如果不点击屏幕,小鸟就会下降 Yi。
小鸟高度等于 0 或者小鸟碰到管道时,游戏失败。小鸟最高高度为 m 。
现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。
数据范围:
5 ≤ n ≤ 10000 ,5 ≤ m ≤ 1000 ,0 ≤ k < n
题解:
• 用 fi,j 表示第 i 列,高度为 j 的最小步数。
• 用 Ai 表示第 i 列可行的最小高度,Bi 表示第 i 列可行的最大高度。
• fi,j = min ( f i-1, j + Yi ,f i-1 , j - Xi * k + k ) ( Ai ≤ j ≤ Bi )
• 这样时间复杂度为 O ( n * m2 ),不满足要求。
• 发现 fi,j 和 f i , j-Xi 的第二项转移只差了 f i-1 , j-Xi 一项,所以我们可以用一个新数组 g 来表示第二项的值。
• gj = min ( gj-k , fi-1 , j-k ) ( 0 ≤ j ≤ m )
• 得到 fi,j = min ( fi-1,j+Yi , gi ) ( Ai ≤ j ≤ Bi );
• 时间复杂度 O ( n * m ),空间复杂度 O ( n * m );
NOIP 2014 解方程
已知多项式方程:
a0 + a1x + a2x2 + .. + anxn = 0;
求这个方程在 [ 1 , m ] 内的整数解(n 和 m 均为正整数)
数据范围
1 ≤ n ≤ 100,1 ≤ m ≤ 1000000,| ai | ≤ 1010000
题解:
由于数据范围非常大,所以直接求解显然是不行的。
一个想法是将所有系数对大质数 P 取模,之后枚举求出取模后的解,多用几个不同的质数几乎可以保证答案不会出错。
然而这样复杂度为 O ( n * m * log n ),复杂度过高,常数也非常大,难以接受。
所以我们可以先对一个小质数 p 取模,求出其模 p 后的所有解。
由于原方程最多只有 100 个解,所以在模 p 之后只有 100 个解。这样在 1000000 以内只有( 1000000 / p ) * 100 个解。之后我们枚举这些解,并对大质数取模进行判断即可。
时间复杂度 O ( n * ( 100000000 / p + p ) ),在 p 取 10000 时最小,为 O ( 10000 n ) 。
空间复杂度 O ( m ) 。
NOIP 2015 子串
有两个仅包含小写英文字母的字符串 A 和 B 。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案。
数据范围:
1 ≤ n ≤ 1000,1 ≤ m ≤ 200,1 ≤ k ≤ m;
题解:
• 用 fi,j,k 表示考虑 A 的前 i 位,选了 j 段,匹配到 B 的第 k 位的方案数。
• 用 gi,j,k 表示考虑 A 的前 i 位,选了 j 段并且第 i 项在第 j 段中,匹配到 B 的第 k 位的方案数。
• fi,j,k = fi-1,j,k + gi,j,k
• gi,j,k = fi-1,j-1,k-1 + gi-1,j,k-1 ( Ai = Bk )
• 由于数据范围较大,直接开三维数组会 MLE,所以我们可以将 i 这一维滚动。
• 时间复杂度 O ( n * m2 ),空间复杂度 O ( m2 );
NOIP 2015 运输计划
L 国有 n 个星球,还有 n-1 条双向航道,第 i 条航道用 xi,yi,zi 来表示,这条航道连通星球 xi 和星球 yi,需要 zi 的时间。这 n-1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。
现在可以将一条航道改成虫洞,即将通过该航道时间变成 0。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
数据范围:
1 ≤ n ≤ 300000,1 ≤ m ≤ 300000
题解:
• 首先可以用 tarjan 求出每组点对的 lca,借此求出点对之间的距离。
• 显然这条权变为 0 的边一定在距离最大的点对形成的链上。
• 我们将这条链拿出来,考虑其他点对形成的链与这条链的关系。
• 如果一条链与最长链相离,那么不管删除哪条边,这条链的权值都不会变。
• 如果一条链与最长链相交,那么我们可以求出它们的公共段,如果删去的边在段中,那么它一定小于等于最长链,否则它的权值不变。
• 所以我们可以将每个点对挂在点上,之后从最长链上的每个点dfs,求出每个点对与最长链的公共段。
• 最后枚举将哪条边变为 0 求出答案即可。
• 时间复杂度 O ( n α ( n ) ) ,空间复杂度 O ( n ) 。
NOIP 2016 换教室
一共有 2n 节课程安排在n个时间段上。在第 i ( 1 ≤ i ≤ n ) 个时同段上,两节内容相同的课程同时在不同的地点进行。其中,牛牛预先被安排在教室 ci上课, 而另一节课程在教室 di 进行。
对于每节课,牛牛可以提出申请改变教室,如果申请通过,牛牛就要去 di 上课,如果没申请或者申请失败,牛牛就要去教室 ci 上课。申请通过的概率为 ki 。学期开始时牛牛可以最多申请改变m节课程的教室。
牛牛所在的学校有 v 个教室,有 e 条道路。每条道路连接两间教室, 并且是可以双向通行的。 由于道路的长度和拥堵程度不同, 通过不同的道路耗费的体力可能会有所不同。当第 i ( 1 ≤ i ≤ n-1 )节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。
问牛牛如何申请可以使期望花费体力最少。输出所花费的体力。
数据范围:
1 ≤ n ≤ 2000, 0 ≤ m ≤ 2000, 1 ≤ v ≤ 300, 0 ≤ e ≤ 90000
题解:
• 这是一道非常好的期望 dp 题。
• 期望 = ∑ 概率 * 权值;
•首先我们可以用 Floyd 将教室两两间的距离跑出来,用 ai,j 表示 i 到 j 的最短路。
•我们考虑确定了申请方案后的做法。
•用 fi 表示在教室 ci 的期望,用 gi 表示在教室 di 的期望。
•如果 i-1 教室被选了;
• fi = ( 1 - ki-1 ) * ( fi-1 + aci,ci-1 ) + ki-1 * ( gi-1 + aci,di-1 );
• gi = ( 1 - ki-1 ) * ( fi-1 + adi,ci-1 ) + ki-1 * ( gi-1 + adi,di-1 );
• 否则:
• fi = fi-1 + aci,ci-1 ;
• gi = fi-1 + adi,ci-1 ;
• 发现由于这个问题没有后效性,所以我们可以一边 dp 一边确定方案,取最优的方案作为答案。
• 用 fi,j 表示前 i 节课一共申请了 j 节课,第 i 节课不申请的期望答案。
• 用 gi,j 表示前 i 节课一共申请了 j 节课,第 i 节课申请不成功的期望答案。
• 用 hi,j 表示前 i 节课一共申请了 j 节课,第 i 节课申请成功的期望答案。
• fi,j = min ( fi-1, j + aci,ci-1,( 1 - ki-1 ) * ( gi-1 , j + aci,ci-1 ) + ki-1 * ( hi-1 , j + aci,di-1 ) );
• gi,j = min ( fi-1 , j-1 + aci,ci-1,( 1 - ki-1 ) * ( gi-1 , j-1 + aci,ci-1 ) + ki-1 * ( hi-1 , j-1 + aci,di-1 ) );
• hi,j = min ( fi-1 , j-1 + aci,ci-1,( 1 - ki-1 ) * ( gi-1 , j-1 + adi,ci-1 ) + ki-1 * ( hi-1 , j-1 + adi,di-1 ) ) ;
• 然而这样做是错的。
• 因为是否申请是在开学时就确定的。而这样写,gi 和 hi 可能一个从 fi-1 转移过来,另一个从 gi-1 和 hi-1 转移过来,这是不合法的。
• 那么问题来了,如何确定哪组 gi,hi 是最优的呢?
• 观察所有转移方程,我们发现提取有关 gi 和 hi 的项之后,全都形如:
• ( 1 - ki ) * gi , j + ki * h i , j
• 所以我们只要将这个值最小的一组 gi,hi 保存下来即可。
• 时间复杂度 O ( n * m ),空间复杂度 O ( n * m );
NOIP 2016 愤怒的小鸟
有一架弹弓位于 ( 0 , 0 ) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形如 y=ax2 + bx 的曲线,其中 a,b 是 Kiana 指定的参数,且必须满足 a < 0 。
当小鸟落回地面(即 x 轴)时,它就会瞬间消失。
在游戏的某个关卡里,平面的第一象限中有 n 只绿色的小猪,其中第 i 只小猪所在的坐标为( xi ,yi ) 。
如果某只小鸟的飞行轨迹经过了 ( xi,yi ),那么第 i 只小猪就会被消灭掉,同时小鸟将会沿着原先的轨迹继续飞行;
如果一只小鸟的飞行轨迹没有经过 ( xi,yi ),那么这只小鸟飞行的全过程就不会对第 i 只小猪产生任何影响。
问最少几只小鸟可以消灭所有小猪。
数据范围:
1 ≤ n ≤ 18,0 ≤ m ≤ 2,0 < xi,yi < 10,输入中的实数均保留到小数点后两位;
题解:
• 由于猪的数量较少,所以我们可以考虑状压 dp 。
• 首先三个点可以确定一条抛物线。
• 由于这条抛物线必定经过 ( 0 , 0 ) 点,所以同时经过两只特定小猪的抛物线最多只有 1 条。
• 所以我们可以预处理二进制数 gi,j 表示同时消灭 i , j 两只小猪的抛物线能消灭的小猪状态。
• 用 fi 表示消灭了 i 状态的小猪的最少使用抛物线数。
• 由于 i 中的每一只没被消灭的小猪都必须被消灭,而消灭的先后顺序又没有影响,所以我们不妨先消灭 i 中未被消灭的编号最小的小猪 x,再枚举和他一起被消灭的一只小猪 j 。
• fi or g[ x , j ] = min ( fi or g [ x , j ] ,fi + 1 );
• 时间复杂度 O ( n * 2n ),空间复杂度 O ( 2n );
NOIP 2016 蚯蚓
蛐蛐国里现在共有 n 只蚯蚓(n 为正整数)。每只蚯蚓拥有长度,我们设第 i 只蚯蚓的长度为 ai ( i = 1,2,...,n ),并保证所有的长度都是非负整数(即:可能存在长度为 0 的蚯蚓)。
每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数 p (是满足 0 < p < 1 的有理数 ) 决定,设这只蚯蚓长度为 x,神刀手会将其切成两只长度分别为 [ px ] 和 x - [ px ] 的蚯蚓。特殊地,如果这两个数的其中一个等于 0,则这个长度为 0 的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加 q ( 是一个非负整常数 ) 。
• 蛐蛐国王希望知道 m 秒内的战况。具体来说,他希望知道:
• m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数)
• m 秒后,所有蚯蚓的长度(有 n+m 个数 )。
• 数据范围:
• 1 ≤ n ≤ 105,0 < m < 7 * 106,0 < u < v < 109,0 ≤ q ≤ 200,1 < t < 71,0 < ai < 108 ;
题解:
• 由于每次蚯蚓都为变长 q 的长度,不会影响两天蚯蚓的大小关系,所以我们可以设定每条蚯蚓的长度为其初始长度,计算当前长度时只要加上经过的时间 t * q 。
• 因为新诞生的蚯蚓与其他蚯蚓所经过的时间不同,为了方便统计,对于t时刻诞生的蚯蚓,我们可以假设他也经过了 t 的时间,将它的长度减去 t * q 。
• 这样用堆来维护所有的蚯蚓,我们就获得了一个 O ( ( n+m ) * log ( n+m ) ) 的算法。
• 然而这个算法的时间复杂度并不满足要求。
• 我们考虑两条初始长度为a和b的蚯蚓 ( a < b ) 。
• 我们先在 t 的时刻把 b 蚯蚓切成两部分,分别为:
• [ ( b + ( t-1 ) * q ) * p ] - t * q 和 ( b + ( t-1 ) * q ) - [ ( b + ( t-1 ) * q ) * p ] - t * q ;
• 然后我们在 t+1 的时刻把 a 蚯蚓切成两部分,分别为:
• [ ( a + t * q ) * p ] - ( t+1 ) * q 和 ( b + t * q ) - [ ( b + t * q ) * p ] - ( t+1 ) * q ;
NOIP 2016 天天爱跑步
天天爱跑步的地图可以看作一棵包含 n 个结点和 m 条边的树。树上结点编号为从 1 到 n 的连续正整数。
现在有 m 个玩家,第 i 个玩家的起点为 Si,终点为 Ti 。每天打卡任务开始时,所有玩家在第 0 秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小 C 想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点的观察员会选择在第 Wj 秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第 Wj 秒也理到达了结点 j 。小 C 想知道每个观察员会观察到多少人。
数据范围:
1 ≤ n , m ≤ 299998
题解:
• 首先我们确定节点 1 为该树的根,之后我们可以将所有跑步的人拆成两段,一段向上,一段向下。
• 这样对于每一段向上的,我们都有两个信息 ai , bi 表示第 0 时刻开始从 ai 走到 bi 点。
• 点i的询问相当于询问经过点i的,满足 deepaj = Wi + deepi 的路径。
• 对于每一段向下的,我们都有三个信息 ai , bi , ci 表示第 ci 时刻开始从 ai 走到 bi 点。
• 点 i 的询问相当于询问经过点 i 的,满足 deepaj-ci = deepi - Wi 的路径。
• 所以对于每一段向上的,我们可以在点 ai 上挂一个 ( deepai ,1 ) 的信息,在点 dad [ bi ] 上挂一个 ( deepai , -1 ) 的信息。
• 这样询问就变成了问子树中所有第一项 = Wi + deepi 的信息的第二项的和。
• 问题转化为每个节点上有一些二维信息 ( x , y ) ,每次询问以 i 为根的子树中 x = ai 的 ∑ y 。
• 再次化简问题,将二维信息变成一位信息。
• 问题转化为每个节点有权值,询问以i为根的子树权值和。
• 有一种巧妙的做法:在 dfs 的时候,我们可以统计所有 dfs 过的点的权值和。
• 在刚刚 dfs 到点 x 时,我们记这个值为 s,在 dfs 完点 x 后,记这个值为 t,那么以点 x 为根的子树的权值和为 t-s 。
• 考虑这个二维信息的问题。我们可以对于每一个信息中的 x,开一个数组 bx,记录所有 dfs 过的点中第一维信息 = x 的 y 的和。那么我们在刚刚 dfs 到节点 p 时,记 s = bap,在 dfs 完节点 p 时,• 记 t = bap,那么 ansp = t-s 。
• 自上而下的那些段同理。
• 时间复杂度 O ( n ) ,空间复杂度 O ( n ) 。
NOIP 2017 小凯的疑惑
小凯手中有两种面值的金币,这两种面值都为正整数且互质。每种金币有无数个。小凯想知道,只用这两种金币不能拼出的最大的面值是多少。
a , b ≤ 109
题解:
• 打表找规律;
• 找到最大的 z,使得 ax + by = z 对于 x , y 没有非负整数解。
• 显然我们可以将 x 加上 b,将 y 减去 a 并保持结果不改变。
• 即我们需要同时满足 x < 0 和 y - a < 0。
• 因为要求最大化 z,所以 x = -1 , y = a - 1 时答案最大,为 a * b - a - b 。
NOIP2017逛公园
策策同学特别喜欢逛公园。公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边。其中 1 号点是公园的入口,N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间。策策每天都会去逛公园,他总是从 1 号点进去,从 N 号点出来。策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,也不希望每天在逛公园这件事上花费太多的时间。如果 1 号点到 N 号点的最短路长为 d,那么策策只会喜欢长度不超过 d+K 的路线。策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗 ? 为避免输出过大,答案对 P 取模。
如果有无穷多条合法的路线,请输出 -1 。
N ≤ 100000,M ≤ 200000,K ≤ 50;
题解:
• 先考虑不存在 0 的情况。
• 注意到我们选择的路径不能离最短路太远,不妨设 f [ i , j ] 表示从 1 走到 i,且当前路径比 1 到 i 最短路径多了 j 的方案数。由于我们后面怎么走都不可能让 j 变小,所以第二维的上限是 K。
• 同时,知道了 i 和 j 之后我们就可以直接的算出现在走了多少距离,枚举下一条边后,就可以直接计算出距离,在得知另外一个点的最短距离的情况下,就可以知道下一个点超出了多少。
• 我们发现这个图的合法路径肯定只有有限条,所以不会成环。以 ( n , i ) 这些点开始,做一次拓扑排序的 dp 即可。
• 现在加入了 0 边之后,就有可能会成环了。
• 但是并不是所有的环都会使得问题无解,比如一个完全孤立开来的 $0 环。
• 我们先从 ( n , i ) 开始做一次 bfs 找出所有能到达的点。然后进行拓扑排序。
• 如果在能访问到的点中有一个点没有被访问过,那么说明一定可以不停的绕,则输出 -1。
• 时间复杂度 O ( N * K ) 。
NOIP2017宝藏
参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 n 个深埋在地下的宝藏屋,也给出了这 n 个宝藏屋之间可供开发的 m 条道路和它们的长度。
小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远,也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路则相对容易很多。
小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。
在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏屋之间的道路无需再开发。
新开发一条道路的代价是:L* K
L 代表这条道路的长度,K 代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。
请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代价最小,并输出这个最小值。
题解:
• 把点按照深度分成一层一层的。
• 如果一个点被分到了更深的层当中,那么最终的答案会变大.
• 不妨设 f [ i , j ] 表示当前枚举了 j 层,且前 j 层的点是 i 这些。
• 在转移的时候,可以枚举i的一个子集 k,然后计算 k 连接到 i 上最小值。
• 预处理 g [ i , j ] 表示 j 这个点连到子集 i 最小的边权是多少,然后 k 只需要枚举每个点累加 g 即可。
• 时间复杂度 O ( 3N * N2 ) 。