23~24 炼石计划 NOIP 练习题部分题解

目录

目录

组名

以下是组名和对应的题单链接,组名仅供参考,并不完全准确:

第 1 组

JOISC2017 火车旅行

倍增处理 \(i\)\(2^j\) 步到达的最左 / 最右位置,转移一定在边界处 .

查询的时候分布扩展左右端点的区间并保持不交就可以了 .

时间复杂度 \(\Theta((n+q)\log n)\) .

和那个模拟赛的差不多 .

IOI2018 会议

可以考虑按最值分成两半,建笛卡尔树后相当于要算每个结点的前缀 / 后缀答案 .

通过仔细地观察转移可以发现就是加和对一次函数取 min,用一个李超树状物即可维护 .

时间复杂度 \(\Theta(n\log n)\),具体看洛谷题解 .

CF1558F Strange Sort

挺神奇的,首先相当于对于所有 \(k\)\(a_i\gets[a_i\ge k]\) 后答案的 max .

考虑对于固定 01 序列怎么做,令 \(f_i\) 是把第 \(i\) 个 0 归位的时间,要求最右边 0 的 \(f\) .

设这个 0 前面有 \(k_i\) 个 1,位置是 \(p_i\),那么:

\[f_i=\begin{cases}0&p_i=i\\\max\{f_{i-1}+1,k_i+(p_i\bmod 2)\}&\text{otherwise.}\end{cases} \]

展开了就是 \(f_i=\max\limits_{j\le i\land p_j\neq j}\{k_j+(p_j\bmod 2)+i-j\}\) .

对于所有 \(k\) 做就相当于单点修改,直接维护就完了 .

APIO2018 新家

离线按时间排序,考虑二分答案,那么只需要判断一个区间内是否所有颜色都出现过 . 问题是经典的,只需要记每个位置的前驱然后查询区间最小值即可 .

这里二分用线段树二分,时间复杂度 \(\Theta(n\log n)\) .

虽然说实际上写起来还是挺麻烦的 .

CTSC2017 密钥

直接枚举 X 在哪里,只需要考虑 X 移动一位的影响,这是容易计算的 .

CF1748E Yet Another Array Counting Problem

相当于问笛卡尔树是给定树的序列个数,直接平方 DP 就完了 .

第 2 组

NOI2016 区间

按区间长度排序然后双指针 .

LOJ552 MIN&MAX I

\((i,j,k)\) 是三元环则满足 \(p_j>\max\{p_i,p_k\}\)\(p_j<\min\{p_i,p_k\}\) .

两种情况对称,只需要考虑计算 \(p_j>\max\{p_i,p_k\}\) 形式的三元环个数 . 注意到对于 \(j\) 存在一个三元环 \((i,j,k)\) 当且仅当 \(p_j\) 不是前缀最大值或后缀最大值 . 那么根据期望线性性只需要对每个 \(j\) 分布计算 \(p_j\) 不是前缀最大值或后缀最大值的概率 .

对于一个 \(j\),容易发现概率 \(P_j=1-\frac1j-\frac1{n-j+1}+\frac1n\)(简单容斥),那么相当于要求一个调和级数,可以分段打表或者使用快速阶乘算法 .

JOISC2023 合唱

首先如果有段数 \(\le k\) 的方案则一定有 \(=k\) 的方案,所以只需要做最小段数 .

注意到答案的形式一定是若干区间 \([l,r]\) 然后第 \([l,r]\) 个 A 和第 \([l,r]\) 个 B 匹配 . 然后有一个朴素 DP,相当于每次 \((\min,+)\) 乘一个 \(w(l,r)\) 表示 \([l,r]\) 内的 A, B 匹配在一起的最小权值 .

容易发现 \(w(l,r)=\sum_{i=l}^r\max\{c_i-l+1,0\}\),其中 \(c_i\) 是第 \(i\) 个 A 前面 B 的个数 . 注意到 \(w\) 满足四边形不等式,所以 DP 答案是凸的(Monge 矩阵最短路凸性) . 于是可以 wqs 二分 .

对于内层 DP,令 \(p_i\) 是第一个满足 \(b_k\ge i\)\(k\),则

\[w(l,r)=\sum_{k=p_{l-1}}^r(c_i-l+1)=s_r-s_{p_{l-1}-1}-(l-1)(r-p_{l-1}+1) \]

其中 \(s\)\(c\) 的前缀和 . 那么其实斜率优化就可以了,总时间复杂度 \(\Theta(n\log n)\) .

LOJ542 序列划分

考虑两个贪心:

  • 按顺序匹配左端点和右端点 .
  • 让第一个左端点和最后一个右端点匹配,剩下的按顺序匹配 .

可以发现两种一定满足一个能跑,然后就完了(

LOJ560 Menci 的序列

注意到 *++++*+ 是一致的,所以可以扫一遍把问题转化成连续 + 不超过 2 个的情况 .

按位考虑,令 \(a_i\) 表示有多少个 + 后面有 \(i\)*,取第一个 \(a_i=0\) 的位置,那么 \(\le i\) 的位肯定都能选上,后面的位因为最多只有 2 个连续的 + 所以全选也无法产生进位,直接全选即可 .

那么可以 \(\Theta(n)\) 完成构造 .

P8978 中位数

首先二分答案,那么问题变成值域只有 1 和 -1 的问题 .

首先注意到每个左端点肯定是匹配最远的右端点操作最优,要不然可以调整过去 . 所以区间肯定只有包含关系 . 然后也可以发现区间肯定互相有交,具体证明比较麻烦可以直接感性一波,所以大概就是一串包含的区间依次操作的结构 .

另一方面可以发现每次操作的时候 1 的量级至少乘 2,那么肯定是 log 轮操作完 .

那么可以设计一个朴素的 DP:\(dp_{i,l,r}\)表示 \(i\) 次操作能否把 \([l,r]\) 推成 1 . 根据最开始的那个性质可以交换值域定义域,变成 \(dp_{i,l}\) 表示能推成 1 的最大 \(r\) .

注意到如果 \(p<q\)\(dp_{i,p}\ge dp_{i,q}\) 那么 \(q\) 一定不可能成为转移点,从而把转移看成若干区间 \([p,dp_{i,p}]\) 则可能有贡献的区间一定不交,也就是说决策点单调 .

其实把式子展开分一下可以发现单调队列就可以实现了,具体可以看一下别的题解,时间复杂度 \(\Theta(n\log^2n)\) .

第 3 组

这一组题总体上意义不大,只有 eps 道有意义的题目,别的都是水题或者模板题(不算那些 20 分的题目).

SNOI2020 水池、SHOI2008 堵塞的交通:线段树维护复杂信息 .

USACO20FEB Help Yourself P

首先用第二类 Stirling 数改成算组合数之和 .

按左端点排序后依次加入每个区间,动态维护 \(dp_i\) 表示右端点为 \(i\) 的子集的答案,每次加入 \([l,r]\) 的时候分类讨论 \(i\)\([l,r]\) 的位置关系即可转移 . 总之就是一个单点修改、区间乘、区间求和,线段树就可以维护了 .

时间复杂度 \(\Theta(nk\log n)\) .

HDU5737 Differencia

用归并树维护序列 \(b\),同时归并的时候维护一下每个元素在左边和右边的排名 . 线段树维护答案,区间赋值的时候因为维护了排名所以只需要在根结点二分一次,往下走可以直接用排名转移,那么就是 \(\Theta((n+q)\log n)\) 的,可以通过 .

第 4 组

CTSC2017 吉夫特

首先根据 Lucas 定理,变成求子序列 \(a_{1\dots k}\) 满足有二进制下的包含关系 \(a_1\subseteq a_2\subseteq\cdots\subseteq a_k\) .

这个直接枚举子集大力 DP 就可以了,时间复杂度 \(\Theta(3^{\log_2\max\{a\}})\) .

十二省联考 2019 异或粽子

经过一些朴素的转化之后就相当于找最大的 \(2k\) 对异或和 .

用一个什么堆内增量式更新的 trick,对每个 \(i\) 维护第 \(k_i\) 大的 \(a_i\oplus a_j\) 加进堆里,初始 \(k_i=1\) . 每次弹堆顶的时候把 \(k_i\) 加一然后更新异或值,这个可以 0-1 Trie 求 .

然后就是 \(\Theta((n+k)\log n\log V)\) 了 .

NOI2023 合并书本

考虑把合并的过程刻画为一个二叉树,每次合并从左儿子合并到右儿子,那么考虑答案可以怎么用树上的信息描述 .

首先是重量的贡献:令 \(a_u\) 表示根到 \(u\) 的路径上有多少往左的步,则重量总共贡献 \(\sum_ia_iw_i\) .

其次是磨损值的贡献:令 \(d_u\) 表示 \(u\) 子树最深的叶子距离 \(u\) 有多远,那么每个非根非叶子结点对答案有 \(2^{d_u}-1\) 的磨损值贡献 .

首先根据排序不等式,只需要升序排序 \(a\) 降序排序 \(w\) 即可取到重量的最小值,所以重量的贡献只和 \(a\) 序列构成的可重集有关 .

考虑从根节点出发,每次分裂一些叶子来得到任意二叉树 . 这里每次分裂一层 \(d\) 相同的叶子,从而每个非根非叶子的结点 \(u\)\(d_u\) 都会改变 . 那么就相当于从原来的可重集 \(S\) 中选一个子集 \(T\subseteq S\) 然后对于每个 \(x\in T\),在 \(S\) 中加入 \(x+1\) 并且令答案 \(c\) 变成 \(2c+|T|-2\) .

这里可以钦定每次分裂下来的叶子对里面至少要选一个在下一次也分裂,否则可以把某个点留到更深的位置再分裂,这样状态大概就是分拆数级别的 . 另外注意到每次分裂的叶子数量单调不降,所以可以在状态里记一个到达这个状态至少分裂的叶子数来限制转移 . 这个剪枝是相当有效的,再加上一个 \(c\ge5\times10^{11}\) 就跳出的剪枝之后 \(n=100\) 时状态数少达 1790,可以轻松通过 .

NOI2018 冒泡排序

限制就是要求每个元素走的时候必须直接一路推过去,不能左右摇摆 . 那么注意到如果有一个三元下降子序列 \(u,v,w\) 的话,这里 \(a_u>a_v\),所以 \(u\) 移动的时候 \(v\) 会往左移动 . 同时 \(a_v>a_w\),所以 \(w\) 移动的时候 \(v\) 会往右移动,这样就出现问题了 . 另一方面可以发现如果所有下降子序列的长度都不超过 2 那么显然是可以满足条件的 . 那么限制也就等价于不存在三元下降子序列 . 根据 Dilworth 定理这个限制也等价于整个排列最多被划分成 2 个上升子序列 .

首先考虑没有字典序限制怎么做,令 \(dp_{i,j}\) 表示已经填好前 \(i\) 个数,最大值等于 \(j\),后面 \(n-i\) 个数的方案数 . 转移的时候枚举最后一个位置填什么,如果填的数比 \(j\) 大那么没有什么特殊限制,否则必须选当前还没有填的数中最小的,而这样的选择方案是唯一的,由 \(dp_{i+1,j}\) 给出 . 所以可以得出转移:

\[dp_{i,j}=\sum_{k=j}^ndp_{i+1,k} \]

转移也是非常的简洁,相当于每次走 \((1,k)\) 步(\(k\ge 0\))的不越过 \(y=x\) 的格路计数 . 那实际上可以改成走 \((1,0)\) 步和 \((0,1)\) 步且不越过 \(y=x-1\) 的格路计数,这个就是 Catalan 数的容斥了,具体可以得到:

\[dp_{i,j}=\dbinom{2n-i-j-1}{n-i-1}-\dbinom{2n-i-j-1}{n-i+1} \]

对于有字典序限制的情况,只需要枚举 LCP 即可转为没有字典序限制的问题 . 时间复杂度单次 \(\Theta(n)\) .

JOI2018Final 毒蛇越狱

\(a,b,c\) 分别是 0 1 ? 的个数,考虑到有 \(\Theta(2^a)\)\(\Theta(2^b)\) 的高维前缀和和 \(\Theta(2^c)\) 的暴力,拼一下就是单次 \(\Theta(2^{\min\{a,b,c\}})\) 的了 . 考虑到 \(a+b+c=L\) 所以实际上是 \(O(2^{L/3})\) 的复杂度,可以通过 .

NOIP2017 宝藏

枚举起点,\(dp_{i,S}\) 表示深度为 \(i\)、选了集合 \(S\) 内的点的答案,这里记深度来限制转移顺序 . 每次转移枚举和 \(S\) 不交的集合,这里可以用枚举子集分析,总共就是 \(\Theta(n3^n)\) 的时间复杂度 .

LOJ504 ZQC 的手办

用超级钢琴那个套路,用堆维护若干区间和最小值位置,每次取堆顶分裂区间 . 这里的区间 checkmax 区间最小值可以线段树维护 . 时间复杂度 \(O((n+\sum x)\log n)\) .

CTT2016 你的生命已如风中残烛

把所有数都减一就变成给一个和为 0 的整数序列问有多少种排法使得每个前缀和都非负,这里每个元素都不小于 -1 .

Raney 引理:对于一个和为 1 的整数序列 \(\{x\}\),恰有一个循环移位使得每个前缀和都是正数 .

这里先把序列每个数都取相反数然后翻转一下,在开头加一个 1,只需要计数每个前缀和都是正数且 1 排在开头的方案 . 由于初始每个元素都是非负的所以现在这个 1 肯定是最大的数,所以一个合法方案的 1 一定在开头,那么根据前文所述 Raney 引理容易发现合法的方案数就是圆排列 \(m!\) .

然而注意到序列中原来就有 \(m-n\) 个 1,每个 1 都可以排开头,从而每个方案恰算重 \(m-n+1\) 次,那么 \(\dfrac{m!}{m-n+1}\) 就是真实的答案了 . 直接计算即可 .

LOJ502 ZQC 的截图

取正整数 \(k\),对每个颜色 \(c\)\(\mathbb F_3^k\) 选取一个随机向量 \(\bm v_c\),查询时只需要求链上每个颜色 \(c\)\(\bm v_c\) 之和,容易发现正确率大概是 \((1-\frac n{3^k})^m\)\(k=40\) 时已经可以接受 .

实际实现需要写三进制不进位加法,这里存三进制数需要压位,算不进位加法可以先打个表 .

第 5 组

USACO19FEB Mowing Mischief P

首先有朴素 DP:

\[dp_i=\max_{j\in\operatorname{LIS}(x[1:i-1])}\{dp_j+(x_i-x_j)(y_i-y_j)\} \]

这里还要求 \((x_j,y_j)\)\((x_i,y_i)\) 的左下角 .

注意到这个式子其实是满足反向的四边形不等式的,所以有递减的决策单调性 . 按 \(x\) 排序后扫描,每个决策点只能向一个区间转移,用线段树分治的方法把区间拆到线段树上,然后用常规的决策单调性算法处理即可 .

时间复杂度 \(O(n\log^2n)\) .

UOJ187 Ernd

就是说平面上有一堆散点 \(p_i\),然后 DP 每次转移二维偏序位置,转一下坐标系把偏序转到左下角就是:

\[dp_i=\max\{\max_j\{dp_j+1\},\max_j\{dp_j-1+(i-j+1)^2\}\} \]

其中第一个 max 的 \(j\) 满足 \(p_j\)\(p_i\) 的左下角,第二个 max 的 \(j\) 满足 \([i,j)\) 内每个元素 \(x\) 都有 \(p_x\)\(p_{x+1}\) 的左下角 .

第一部分转移可以树状数组做二维偏序查找,第二部分转移可以使用斜率优化或者决策单调性优化做 .

总之就是 \(\Theta(n\log n)\) 了,可以通过 .

LOJ553 MINIM

玄学复杂度分析题,对暴力 DP 每层缩连续段就能过了 .

具体复杂度分析可以看官方题解 .

LOJ501 ZQC 的树列

就是相当于把 \(n\) 分成若干 \(2^k\)\(2^k-1\) 的乘积 . 前面平凡,后面从大到小贪心选,需要特判 \(63\),因为这里 \(63\)\(1\times3\times 7\times 15\) 的因数 .

NAIPC2016 Jewel Thief

结论:模 \(k\) 余数相同的位置有决策单调性 .

然后分治就可以了 . 有点神秘 .

AGC061E Increment or XOR

+1 操作不进位高位一定没有影响,进位一定是将低位全部归零 .

\(dp_{i,U,S,T}\) 表示 +1 最高影响到第 \(i\) 位、每个操作的奇偶性状态为 \(U\)、低位的起始状态和终止状态分别为 \(S,T\) 的最小步数 . 那么转移 \(f_i\to f_{i+1}\) 就是:

  • 没有进位:那就是只和 \(U\) 相关,比较平凡 .
  • 由 +1 进位:那么考虑就是一个这样的结构:

    \[dp_{i+1,U,S,T}\gets dp_{i,U_1,S,1}+dp_{i,U_2,1,1}+\cdots+dp_{i,U_k,1,T} \]

    这是一个最短路的形式,Dijkstra 即可 .

从而可以 \(\Theta(2^{2n}\log V)\) 解决 .

SDOI2019 染色

口胡一下,不写了 .

首先有朴素 DP:\(dp_{i,j,k}\) 表示前 \(i\) 列上面填 \(j\) 下面填 \(k\) 的方案数 .

然而注意到如果一列有数了那么只需要 \(O(c)\) 的状态,如果一段列是空的可以预处理出来转移,那么状态就是 \(O(nc)\) 的了 . 这里用数据结构优化一下就可以到 \(\Theta(n)\) 的复杂度了 .

AGC017F Zigzag

首先有朴素轮廓线 DP,需要记一下轮廓线、线的数量、线的深度和最后两根线之间的距离,然后就 \(\Theta(2^nmn^2)\) 了 .

然而距离实际上没啥用,每次往右走的时候把那个轮廓线也贴过去就可以省掉那一维了 .

时间复杂度 \(\Theta(2^nnm)\),可以通过 .

CF756E Byteland coins

首先考虑一个朴素的 DP:\(dp_{i,j}\) 表示前 \(i\) 种金币总面额为 \(j\) 的方案数,这样就是一个多重背包 .

注意到 \(dp_{i,j}\) 有贡献当且仅当 \(j\equiv m\pmod{d_i}\)(在模 \(d_i\) 意义下考虑),令 \(t_{i,j}=dp_{d_ij+m\bmod d_j}\),则有:

\[\max\{j\mid t_{i,j}\neq 0\}\le\sum_{j=1}^ib_j\cdot\dfrac{d_j}{d_i} \]

因为只有 \(\frac{d_i}{d_j}\) 的倍数对应的位置才可能有贡献,总共有 \(b_j\cdot\frac{d_j}{d_i}\) 个 .

另外可以发现 \(d_i\) 至多走 \(k\) 步就至少除以二,那么可以估计状态数的上界:

\[\sum_{i=1}^n\max\{j\mid t_{i,j}\neq 0\}\le\sum_{i=1}^n\sum_{j=1}^ib_j\cdot\dfrac{d_j}{d_i}=\sum_{j=1}^nb_j\sum_{i=j}^n\dfrac{d_j}{d_i}\le\sum_{j=1}^nb_j\sum_{p\ge0}\dfrac k{2^p}=2k\sum_{j=1}^nb_j \]

这个量级是可以接受的,使用前缀和优化多重背包就可以做到 \(\sum\max\{j\mid t_{i,j}\neq 0\}\) 的复杂度 . 需要写一些简单的高精度运算 . 总时间复杂度 \(O(\log^2m+k\sum b_i)\),可以通过 .

AGC013D Piling Up

就是从所有起点出发的 N-bridge 计数这种东西,平行的只算一遍 .

路径计数就直接朴素 DP 就行了,对于平行的只算一遍可以钦定经过 0 .

时间复杂度 \(\Theta(nm)\) . 让它再快一点应该非常麻烦,但是我猜也不是完全不可能做 .

UOJ22 外星人

首先给 \(a\) 排序,令 \(dp_i\) 表示 \(x=i\) 时用 \(\le i\)\(a\) 的最大值和方案数 . 那么每次转移到 \(dp_{i\bmod a_k}\) 然后方案数乘上 \((i\bmod a_k,i]\) 间的数随便排的方案数即可 .

时间复杂度 \(\Theta(nx)\) .

ZJOI2012 波浪

就是比较套路的那种 DP,\(dp_{i,j,k,l}\) 表示放了 \(1\dots i\) 的数,形成 \(j\) 个连通块,目前产生的贡献为 \(k\),有 \(l\) 个边界已经被用过,然后讨论一下即可转移 .

时间复杂度 \(\Theta(n^4)\),需要使用数据类型分治要不然会 T . [JOI Open 2016] 摩天大楼这个题做法一样但是阳间一点 .

JOISC2020 遗迹 3

从后往前考虑可以得到从 \(h\) 生成 \(A\) 的方式:如果当前柱子后面有 \(1\dots v\) 的柱子各一根,那么它之前的高度 \(\le v\) 的柱子会被震没 . 那么只需要从后往前考察每个时刻的 \(v\) 是多少,类似一个后缀 mex 的模式 . 后称这 \(v\) 个柱子是标准柱 .

\(dp_{i,j}\) 表示考虑后 \(i\) 个柱子,当前 \(v=j\) 的方案数 . 设 \(c_0\) 表示后 \(i-1\) 个柱子中消失的数量,\(c_1\) 表示存在的数量 .

转移考虑分类讨论:

  • 如果 \(i\) 钦定消失,则从 \(dp_{i-1,j}\) 转移,有 \(j-c_0\) 种选法 .
  • 如果 \(i\) 钦定保留:
    • 如果 \(i\) 加入后不改变 mex,也就是 \(i\) 的高度大于 \(j+1\),那么考虑延迟处理它的贡献,直接由 \(dp_{i-1,j}\) 转移 .
    • 如果 \(i\) 加入后改变 mex,也就是 \(i\) 的高度等于 \(j+1\):考虑枚举一个新阈值 \(k\),从 \(dp_{i-1,j}\) 转移到 \(dp_{i,k}\) . 系数包含三个部分:选定标准柱的位置 \(\binom{c_1-j}{k-j-1}\)、确定当前柱子的长度 \(k-j+1\) 和延迟考虑的 \(k-j-1\) 个位置的贡献 .
      对于延迟考虑位置的贡献,只需要计算将 \(n\) 个石柱震为高度连续的(初始)状态数 \(t_n\) . 可以同样考虑一个 DP,枚举编号最小的柱子的高度可以转移:

      \[t_n=\sum_{i=1}^n\dbinom{n-1}{i-1}(i+1)t_{i-1}t_{n-i} \]

综上可以得到一个 \(\Theta(n^3)\) 的做法,可以通过 . 使用卷积可以简单优化到 \(\Theta(n^2\log n)\) .

APIO2016 烟火表演

考虑一个朴素 DP 就相当于每个点有一个凸包,每次转移给每个凸包和一个绝对值函数 Minkowski 和然后对应位求和 .

因为 Minkowski 和的是一个两段的分段函数,其实就是平移一下然后加条线维护一下凸包 . 那么可并堆维护拐点就可以完成所有需要的功能 .

时间复杂度 \(\Theta(n\log n)\) .

第 6 组

NOI2023 桂花树

可以把两个限制看成虚树的形式:

  1. \(1\dots n\) 构成的虚树等于它本身 .
  2. 对于每个 \(i\)\(1\dots i\) 构成的虚树中结点编号都不大于 \(i+k\) .

考虑依次加入每个结点,每次可以有几种方案:

  • 插在某个边上 .
  • 挂在某个叶子下面 .
  • 从一条边上接出来,顺便附带一个 \(\le i+k\) 的空位放在那条边上(这个空位留着以后填) .
  • 填一个空位 .

可以考虑维护一个编号的滑动窗口然后状压每个待确定结点的状态,那么每个转移就都可以运作了 . 时间复杂度单次 \(\Theta(mk2^k)\),在洛谷上需要卡一下常数 .

JOI2019Final 独特的城市

注意到考虑距离点 \(u\) 最远的点 \(v\),那么对于 \(u\) 的独特的城市一定在链 \(u-v\) 上 . 根据经典结论可知 \(v\) 一定是直径端点,那么只需要对于两个直径端点分别跑一遍然后取 max 即可 .

对于一个直径端点 \(p\),以 \(p\) 为根 DFS 并动态维护一个栈表示当前的独特的城市,进而可以维护答案 . 这里做一个长链剖分,DFS 时先进入最深的儿子再进入其它儿子,这样处理 \(u\) 的儿子时 pop 掉的 \(u\) 以外的位置一定不会再被加回来,于是每个点 \(u\) 被 push \(\deg(u)\) 次,总共 push \(\Theta(n)\) 次 . 那么总时间复杂度为 \(\Theta(n)\) .

LOJ6020 寻找 LCT

计算把重心调整到每个位置的最少 link-cut 操作次数然后和 \(k\) 比较 . 先找到原树的重心 \(c\),然后把重心调整到 \(x\) 的话,一定是割掉一些 \(c\) 的子树,然后挂到 \(x\) 上面 . 那么把子树大小处理出来二分就可以了 . 这里也可能是让 \(x\) 所在子树对应的儿子先作为重心然后在调整到 \(x\) 上,需要讨论一下 . 时间复杂度 \(\Theta(n\log n)\) .

CSP-S2019 树的重心

类似前面那个叫寻找 LCT 的题,以重心为根,讨论每个点割哪条边可以让它变成新重心就可以了 . 这里需要一个单点修改区间求和,可以树状数组维护,时间复杂度 \(\Theta(n\log n)\) .

也可以用做子树重心的方法线性处理每个子树重心和子树补重心,不过比较麻烦 .

SNOI2019 积木

黑白染色后可以看成给出一张二分图的两个最大匹配,要求走一条交错路把一个变成另一个 . 取两张图的对称差就变成有一些连接两个未匹配点的链和一些环,需要走一条路把这些都消掉 . 首先把链走了就只剩环了 . 此时把匹配的点缩起来,在 DFS 树上走欧拉序,每次遇到环就在环上走一圈回来,这样就可以把每个环消掉了 . 那么这题就做完了 .

USACO17DEC Push a Box P

直接大力 BFS,那么就变成要把箱子那个格删掉两个点是否连通,这个在圆方树上随便做一下就对了 . 然后大概就是一个 \(\Theta(nm\log nm)\) 的复杂度,可以通过 .

NOIP2017 逛公园

大概就是 \(dp_{u,k}\) 表示走到点 \(u\) 长为最短路加 \(k\) 的路径数量,转移可以直接记忆化搜索 .

CSP-S2021 交通规划

首先考虑 \(k=2\),只需考虑两个附加点异色 . 那么肯定是同色部分构成两个连通块,分别连通两个附加点,这就是最小割,这里平面图最小割可以改成对偶图最短路算 .

对于 \(k>2\) 可以通过一些深刻的观察得到一定是同色点两两匹配,用连通块连通,如图:

那么两两匹配的代价就是 \(k=2\) 的情况,可以最短路求 . 对于总共的答案可以区间 DP 解决,类似春测圣诞树那个题 . 那么就单次 \(O(k\cdot nm\log nm+k^3)\) 了 .

JSOI2008 最小生成树计数

考虑 Kruskal 算法的过程,边权一样的边在加完后连通性必然是一致的,所以每种边权独立 . 对于一种边权就是要计算把其他点缩起来后的生成树个数,可以使用 Matrix-Tree 定理,时间复杂度 \(\Theta(n^3)\) . 然而也可以不使用,由于数据保证具有相同权值的边不会超过 \(c=10\) 条,所以可以直接 \(O(m2^c)\) 暴力枚举 .

IOI2020 连接擎天树

首先注意到如果图有多于一个环那么在两个环上分别选一个点就可以得到至少 4 条简单路径,所以答案一定是基环树森林 . 然后就平凡了 .

ECF2018 异国情调的……古城

首先考虑对每个 \(w\) 算只加边权 \(\le w\) 的边的答案,差分一下即可得到每种边权的出现次数,于是就把问题转化为了边权为 1 的问题 .

这里直接大力并查集维护,但是如果一条边没用了就把它去掉,复杂度可以均摊到 \(O(mw\alpha(n))\) .

LOJ566 yanQval 的生成树

首先容易发现 \(\mu\)\(a\) 的中位数 . 那么可以想到一个朴素算法:枚举 \(\mu\),称 \(w_i<\mu\) 的边为白边、否则为黑边,那么就是要在两种边中分别选 \(\left\lfloor\dfrac{n-1}2\right\rfloor\) 条,求最大生成树 .

这个就是一个经典的 wqs 二分,考虑二分斜率 \(k\),每次把白边权值加 \(k\) 然后求最大生成树判定即可 .

然而注意到对于 \(\mu,k\) 来说,白边的权值 \(w\) 最终变成了 \(\mu+k-w\)、黑边的权值 \(w\) 最终变成了 \(w-\mu\) . 边权全体加 \(\mu\) 不影响最大生成树形态,那么可以改成白边变成 \(2\mu+k-w\)、黑边不变 .

那是不是可以直接二分 \(2\mu+k\) 解决? (智将)虽然看起来有点离谱,但是确实是可以的,具体证明看官方题解 .

于是问题就被一次二分解决了,时间复杂度 \(\Theta(m\log n\alpha(n))\) .

第 7 组

湖北省选模拟 2023 棋圣

首先考虑树怎么做,黑白染色后考虑到一次操作会让每个棋子所在点的颜色翻转,那么令 \(c_{i,j}\) 表示所在位置颜色为 \(i\)、自身颜色为 \(j\) 的棋子数量,则答案有上界 \((c_{0,0}c_{1,1}+c_{0,1}c_{1,0})\max w\)(移到边权最大的边的两侧). 观察可以发现这个上界在存在度数大于 2 的点的时候是一定取到的,那么只有链的情况需要额外考虑 .

此处可以考虑一个 DP:\(dp_{i,l,r}\) 表示考虑到点 \(i\)\(i\) 上聚集了 \([l,r]\) 编号的棋子的答案,转移时枚举下一个有棋子的位置 \(j\) 和它对应聚集的编号段 \([r+1,k]\) . 考虑到 \(j-i\) 不大于编号为 \(r+1\) 的棋子和编号为 \(r\) 的棋子之间的距离,所以 \((i,j,k)\) 的级别是 \(O(n^2)\) 的,从而 DP 的复杂度是 \(O(n^4)\) 的 . 实际跑起来比较松,可以通过 . 可以进一步优化到 \(O(n^3)\),不过不写也能过,就摆了(

对于任意图的情况是容易扩展的 . 对于非链的情况,如果图是二分图,那么和树的情况一致;否则一定存在奇环,此时可以通过奇环任意切换奇偶性,从而可以类似导出答案即为黑棋子数乘白棋子数乘最大边权 .

那么整个问题就在 \(O(n^4)\) 的时间复杂度内被解决了 .

P9591 PFL 变换

注意到直接取 \(\operatorname{highbit}(n)\)\(\operatorname{highbit}(n)-1\) 即可异或得到 \(2^{\lfloor\log_2 n\rfloor+1}-1\),然后补若干个 \(2i\)\(2i+1\) 调整到 \(m\) 次操作即可 . 此处如果奇偶性不对就把 \(\operatorname{highbit}(n)-1\) 改成 \(\operatorname{highbit}(n)-2\) .

然而发现 \(m=1\)\(n-m\le 2\) 会炸,特判一下就可以了 .

UOJ75 智商锁

智商题是吧 . 考虑到用一条边把两张图连起来得到的新图的生成树个数是两张图生成树个数的乘积,随机 \(10^3\) 张点数为 12 的无向图,然后 Matrix-Tree 定理求出每张图的生成树个数 \(f_i\) . 试图找一个四元组 \((a,b,c,d)\) 使得 \(f_a\cdot f_b\cdot f_c\cdot f_d\equiv k\pmod p\),这个可以简单平方算(找不到的概率是极低的,可以看做不可能发生).

虽然感觉上已经过了,但是由于某些原因需要特判 \(k=0\) .

UOJ216 Jakarta Skyscrapers

首先如果 \(b=1\) 可以通过依次计算 \(a-1,\,a-2,\,2,\,a-4,\,4,\,\cdots\) 来在 \(3\log_2 a\) 次内得到任意数 .

否则,如果 \(c>\max\{a,b\}\)\(\gcd(a,b)\nmid c\) 无解,否则先辗转相除得到 \(\gcd(a,b)\)(这一步可以使用上一行的方法),然后可以通过 \(a\) 减若干个 \(\gcd(a,b)\) 得到 \(c\)(这里也是上一行的做法).

每次辗转相除 \(x\bmod y=x-\lfloor\frac xy\rfloor y\) 需要 \(3\log_2(\frac xy)\) 次操作,考虑到所有 \(\frac xy\) 的乘积不超过 \(n\),所以这部分的总操作次数不超过 \(3\log_2n\) 级别 . 综合可得最大操作次数 \(6\log_2n\),可以通过 .

WF2014 Baggage

感觉有点搞笑啊,模拟一下样例大概就知道怎么做了(

大概是这样一个过程:首先考虑一个 \(\texttt{__BABABABABABA}\),然后用两步操作 \(\texttt{__BABABABABABA}\to\texttt{ABBABABABAB__A}\to\texttt{ABBA__BABABBAA}\) .

考虑去掉左右 4 个字符中间的部分,假如完成了这个部分的排序,现在变成 \(\texttt{ABBAAABB__BBAA}\),然后可以构造:\(\texttt{ABBAAABB__BBAA}\to\texttt{A__AAABBBBBBAA}\to\texttt{AAAAAABBBBBB__}\),这样就排完了 .

也就是说可以 4 步让 \(n\to n-4\),从而得到一个 \(n\) 步的做法 . 注意到每次操作相邻相同的位置个数第一次最多增加 1,后面每次最多增加 2,于是答案不小于 \(1+\lceil\frac{2n-3}2\rceil=n\),从而 \(n\) 步是步数最小的解 . \(n\le 8\) 特判 .

LOJ508 失控的未来交通工具

一条路径可以表示为若干个环和一条简单路径的组合,所以相当于就是两个等差数列求交 .

LOJ539 旅游路线

\(dp_{i,p}\) 表示位于景点 \(i\) 且在 \(i\) 位置加油、剩余钱数为 \(q\) 时的最大路程 .

每次转移枚举下一次加油的路程,只需要对于每个 \((i,j,c)\) 处理两点间经过不超过 \(c\) 条道路的最大路程,这个可以倍增预处理(或者可以看成向量乘矩阵的幂什么的). 每次询问的时候二分出最小的 \(dp_{s_i,q}\ge d_i\) 的位置即可 .

LOJ538 数列递推

感受一下对于足够大的部分序列一定单调 . 首先注意到如果相邻两项同号或某一项的绝对值大于前一项那么后面单增 . 于是令 \(b_i=|a_i|\),可以得到 \(b_i=b_{i-2}-kb_{i-1}\),从而 \(b_{i-2}=kb_{i-1}+b_i\ge(k+1)b_i\) .

那么每两步至少除以 \(k+1\),所以至多 \(2\log_{k+1}|a_0|\) 步结束,从而 \(O(\log a)\) 项后一定单调 .

那么直接模拟的时间复杂度就是 \(O(n\log a)\) 的了 .

LOJ541 七曜圣贤

如果只考虑插入得到的 mex 是 \(x\),删除元素的最小值是 \(y\),那么答案就是 \(\min\{x,y\}\) .

前者直接单调指针维护即可 . 后者可以考虑恢复的一定是删除的一个前缀,那么维护一个单调队列就可以线性了 .

SDOI/SXOI2022 进制转换

令阈值 \(B_1,B_2=\Theta(\sqrt n)\) 分别是 2, 3 的幂,按 \(B_1,B_2\) 高低位分治可以将所求转为:

\[\sum_{i_1+B_1j_1=i_2+B_2j_2}a_1(i_1)a_2(j_2)b_1(i_2)b_2(j_2) \]

其中 \(0\le i_1<B_1,\,0\le i_2<B_2\)\(a_1(i)=a_2(i)=y^{a(i)},\,b_1(i)=x^iz^{b(i)},\,b_2(i)=x^{iB_2}z^{b(i)}\) .

为了限制 \(i_1+B_1j_1\le n\) 可以考虑限制 \(j_1<\lfloor\frac n{B_1}\rfloor\) 然后以 \(O(B_1)\) 的代价修正 .

原式限制即为 \(i_1-i_2=B_2j_2-B_1j_1\),可以考虑分别计算两侧的分布:

\[\begin{aligned}&f_n=\sum_{i_1-i_2=n}a_1(i_1)b_1(i_2)\\&g_n=\sum_{B_2j_2-B_1j_1=n}a_2(j_1)b_2(j_2)\end{aligned} \]

这里只需要 \(n\in[-B_2,B_1]\) 的点值 .

对于 \(f\) 可以考虑一点点 lifting 上去,假设目前的限制是 \(0\le i_1<2^{d_1}\)\(0\le i_2<3^{d_2}\) . 如果要提升到 \(0\le i_1<2^{d_1+1}\),注意到 \(a_1\) 在 2 进制下按位独立,所以有 \(f'_n=f_n+a_1(2^{d_1})f_{n-2^{d_1}}\) . 提升 \(i_2\) 类似 .

每次取 \(2^{d_1}\)\(3^{d_2}\) 中较小的进行提升,这样 \(2^{d_1}\)\(3^{d_2}\) 随时同阶,这部分的时间复杂度就是 \(\Theta(\sqrt n)\) 的 .

对于 \(g\) 注意到对于每个 \(j_2\) 只有 \(O(1)\) 个合法的 \(j_1\),暴力即可 .

总时间复杂度单次 \(\Theta(\sqrt n)\) . 如果计算 \(f\) 直接使用卷积可以平衡到 \(\Theta(\sqrt{n\log n})\),也可以通过 .

JOISC2021 活动参观 2

按位贪心,之后就是要计算选完之后最多能参加多少活动 . 根据经典贪心就是按左端点排序选 .

可以 set 维护当前的空位,然后倍增处理一段内最多能放多少个不交区间 . 时间复杂度 \(O(n\log n)\) .

第 8 组

U313395 二项式展开

虽然也挺简单的,但是前面没人做,就写一下题解 .

首先单位根反演转成算 \(\displaystyle\dfrac1c\sum_{k=0}^{c-1}(a\omega_c^k+b)^n\) . 由于模 19260817 意义下不一定存在单位根所以需要使用一些奇怪的方法算 . 具体就是先用 \(\omega_c^{0\dots c-1}\) 的线性组合表示每个数(这种表示方法对于每个数不是唯一的但是不重要),乘法暴力循环卷积,这样可以 \(O(c^3\log n)\) 算出来答案用单位根表示的结果,最后可以用浮点数四舍五入得到真实的整数值 .

总共 \(O(c^3\log n)\) 可以直接过,如果使用卷积可以到 \(O(c^2\log c\log n)\) .

但是这个题把 std 拉下来跑 \(c=1\) 跑不对(然而数据并没有 \(c=1\)).

upd. 根据 joke3579 指导只需要算 \([x^0]((ax+b)^n\bmod(x^c-1))\),循环卷积快速幂即可 \(O(c^2\log n)\) 或者 \(O(c\log c\log n)\)2024.10.17 闲话).

POI2011 SEJ-Strongbox

根据 Bézout 定理,令 \(d\) 是满足 \(d\mid\gcd(n,m_k)\) 且对于 \(i<k\)\(d\nmid\gcd(n,m_i)\) 的最小正整数,\(\frac nd\) 就是答案 .

此处可以直接枚举因数打标记,对于每个因数 \(d\mid\gcd(n,m_k)\) 只需要枚举所有素因数 \(p\mid d\) 然后标记 \(\frac dp\),这样这部分总计就是 \(O(d(n)\omega(n))\) 的了,可以接受 .

总复杂度 \(O(\sqrt n+k\log n+d(n)\omega(n))\) .

蓝桥杯 2020 质数行者

首先容斥改成算 \(O(1)\) 组没限制的答案,三维的情况可以对一维情况做两次二项卷积得到,这里平方暴力就可以了 .

时间复杂度 \(\Theta(n^2)\) .

WC2016 论战捆竹竿

令序列 \(a\) 包含字符串的所有周期长度,那么就是要算 \(\sum a_ix_i\)\([0,w-n]\) 中能取到的值的个数 .

这是经典的同余最短路问题 . 根据 Border Theory 可知 \(a\) 可以划分成 \(O(\log n)\) 个等差数列,对于每个等差数列连的边就是若干个环,那么只需要对每个环分别算然后合并,对于每个环来说可以从最短路最小的地方单调队列松弛掉每个点 . 这里切换等差数列的时候需要切换模数,其实也是差不多处理,不详细展开了 .

时间复杂度 \(O(n\log n)\) . 可能 UOJ 的 Hack 确实有点高明,放个提交记录:Submission .

CF1821F Timber

熟练题!首先根据 DP 可以得到答案为 \([x^{n-m(k+1)}]\left(\dfrac{2-x^k}{1-x}\right)^m\),可以把分子分母拆出来分别算然后 \(\Theta(n)\) 卷积 .

省选联考 2020 组合数问题

转写为牛顿级数 \(\displaystyle f(x)=\sum_ih_i\dbinom xi\),那么就是要计算

\[\sum_{i=0}^mh_i\sum_{k=0}^n\dbinom ki\dbinom nkx^k=\sum_{i=0}^mh_i\dbinom nix^i(1+x)^{n-i} \]

这里可以把 \(h_i\) 里面带的阶乘和组合数的阶乘消一下,这样就不需要求逆元了 . 时间复杂度 \(\tilde\Theta(m^2)\) .

P4707 重返现世

首先用 min-max 容斥:

\[\mathbb E(\operatorname{kthmax}(S))=\sum_{\varnothing\neq T\subseteq S}(-1)^{|T|-k}\dbinom{|T|-1}{k-1}\mathbb E(\min(T)) \]

其中不难得出 \(\mathbb E(\min(T))=\frac{m}{\sum_{i\in T}p_i}\) .

考虑到 \(m\) 比较小,于是令 \(dp_{i,j,k}\) 表示前 \(i\) 个元素中 \(\sum_{i\in T}p_i=j\) 时的答案,转移就是背包 . 关于组合数移动一位可以用 \(\binom nm=\binom{n-1}{m-1}+\binom{n-1}m\) 拆 . 具体实现的时候需要滚动数组一下 .

时间复杂度 \(\Theta(nm(n-k))\) .

LOJ510 北校门外的回忆

想着 CSP 前先发表了吧,这题先鸽着~

posted @ 2024-10-24 19:22  Jijidawang  阅读(198)  评论(0编辑  收藏  举报
😅​