2022.4
四月了啊...
推一首歌吧 当时小椿沿海边跑的时候的 BGM,经典青梅竹马打不过天降妹子
反正在家网课,就顺便停课了
改的都是简单题,难题都弃了
好菜啊
好像没有那种花一下午时间研究一个算法的耐心了
ε-(´∀`; )
4.1
T1
不算太难,不写了
T2
给你一个 个点的无向图,计数满足 个限制的生成树数量,每个限制是一个点集 ,要求 在生成树上的导出子图联通。
。
生成树计数肯定是矩阵树定理。
考虑每一个限制 , 的导出子图的边数 ,且该限制被满足当且仅当取到等号。
我们考虑给原图每条边 赋上边权 , 为同时包含 和 的限制个数,我们发现这样,对于它的生成树 ,边权和 ,等号取到当且仅当所有限制都被满足,所以满足条件的生成树就是最大生成树。
最大生成树就是经典做法了,忘了的话去看一眼 Luogu P4208 [JSOI2008]最小生成树计数。
还有 的计算用 bitset 优化一下就是 。
总复杂度 。
T3
答案文件 10.1 K
长度为 的序列 ,你有从中选出 个区间,区间的权值定义为所包含数的和。要求 个区间能覆盖整个序列,并且权值和最大,求最大权值和。
。
首先是一些 key observation
若两个区间为包含关系,那么我们显然可以舍弃被包含的区间,然后选择当前未选择的区间中权值最大的。因为最多 个不包含的区间就可以覆盖整个序列,所以前 大的区间一定被选。
进一步观察,假设最优解选择了前 大的区间 ,此时剩下 个点没有被覆盖,那么剩下的 个区间一定两两不相交,并且每个区间至少覆盖 个未覆盖点中的一个。因为,若两个区间 相交,我们显然可以选 代替,再选择当前未选择的区间中权值最大的,一定不劣。
所以我们先选上前 大的区间,计算它们的权值和以及它们覆盖的位置,然后再找到第 到第 大的区间。这个可以二分权值,然后再用树状数组,set 之类的东西求大于等于当前二分权值的区间个数,覆盖位置,权值和等等,这部分复杂度就是 ,但若干区间权值相同的情况真的是及其恶心。
然后我们逐个加入第 到第 大的区间,设当前未被覆盖的位置是 ,我们需要对每个 求出 ( 是 的前缀和),然后把这些值塞进 set 里,每次求出前 大的数的和,再加上 就相当于选出了 个区间覆盖了所有未覆盖点。随着 增大,会有一些 被删除,所以要动态维护那个 的值(插入,删除,查询前 大的数的和),搞一个 set 之类的数据结构就可以做了,这部分是 的。
据说还有 wqs 二分 + 线段树维护 DP 的做法,不太会...好像只有我写的题解做法还写了 10K
/tuu/tuu/tuu
4.2
T1
给你长度为 的字符串 和正整数 ,判断 的每个前缀是否形如 , 可以为空串。
。
没一眼切是不是应该去死
枚举 ,判断 是否能作为 ,所以只需求 。
后缀数组,哈希都可以,新学了一下 Z 函数,这样就可以 。
周三没有模拟赛,复习一下字符串,写个字符串总结(flag
T2
这个是原题 CF1120D 加了一个求方案数,(其实上一题也是原题 CF526D)
所以就不写了
有 DP 做法,也有最小生成树做法(能不能求方案数?)(去看题解)
T3
ARC016D
这个二分很有意思的欸
题意很长不写了,总是是求期望,也容易列出状态转移方程
边界
但这个是有后效性的,不过后效性只与 有关,我们考虑钦定 ,然后直接按方程转移,最后在看算出的实际 是否等于 。
我们把这样计算出来的 看成是 的函数 ,想一想就有 ,所以就有 他是有单调性的,可以二分出 的 ,也就是答案。
至于这个 应该也可以感性证明,考虑按拓扑序归纳,考虑 减小了 , 不会变所以它的导数是 , 如果从 转移来那么 ,如果从 转移来,那么 也是成立的,所以就证明了恒有 。
4.4
T1 水题,T2交互
T2
猜树题,你要猜一颗二叉搜索树(按编号),可以 query(x,l,r)
询问 的子树是否恰好包含 的点,询问次数是 。
想到单调栈求笛卡尔树的做法,我们也考虑使用单调栈。
按标号顺序依次加点,栈中维护一条最右链,发现是可以一次询问出当前点是否在栈顶节点的右子树。
总之要想到单调栈。
T3
你要构造一个 个点的简单图,每个点的度数至少为 ,且图中所有度数为 的点不能相邻,最小化边数。
。
并不是构造题,因为重点在于求最小边数。
我们把点按度数等于 和大于 分类,设等于 的集合大小为 ,那么两部分之间有 条边,等于 的点之间不能连边,大于 的点之间可以连边,设连了 条。
容易列出不等式 ,为了 最小,解出 。那么总边数 就等于 , 为 或 时取得最小值。
得到了 之后构造方案就很简单了。
4.5
T1
给你一棵树,然后三个操作:
- 向集合中加入一个数
- 删除集合中的一个数
- 询问集合中 的数编号的节点到 的最小距离
,强制在线。
很显然的点分树,对每个点用线段树维护它点分树上的后代即可。复杂度 。
T2
the same as 4.2 T3
T3
经过一个经典的卡特兰数模型 ,问题转化成了求 ,其中 表示 的质因数分解中 的次数。
。
首先有
进一步考虑什么时候才是奇数,我们发现当且仅当对于一个 ,存在 使得 ,所以我们把 转成 进制从高往低逐位考虑即可。
复杂度瓶颈是进制转化,所以是 的。
好困,,所以写的好像很简略。
今天还行,三道题都是自己想的,不过赛时摸的有点多,就写了一道。
这几天题也不太难,天天都是一车 AK,不过跟我垫底关系不大。
4.7
T1
抽象出题意就是,给你一个长 的 01 序列,你可以进行 次操作,每次选择一个长 的区间全部赋成 ,求操作后最少剩下几个 。
。
不要想贪心了,不要想贪心了,不要想贪心了,虽然看上去很对但它就是错的。
先考虑一个看上去没什么前途的 dp, 表示前 个数,进行了 次操作,最少的剩下 的个数。
转移很简单:,时间复杂度 。
关于这种有限制次数的问题,如果不限制次数,很容易求解最优方案,就要想到 wqs 二分。
答案的凸性容易证明,所以通过 wqs 二分就做到了 。
T2
给你一个平面图,每次操作修改边权,你需要回答每次修改后的最小生成树,强制在线。
。
首先肯定想到 LCT,如果是边权只能变小就非常容易了,但我们无法在一条树边变大后快速判断它还在不在生成树上。如果可以离线,可以通过线段树分治等做到 ,但即使这样,巨大的常数也是很难通过的。
考虑本题的特殊条件,实际上,平面图的最小生成树有下面的结论:
这真是太妙了,看完题解激动了好长时间。
平面图的最小生成树的补集是其对偶图的最大生成树。
证明是容易的,把边集分成两部分后,平面图和对偶图两者任一个不连通当且仅当另一个中存在环,所以当两者都联通且不存在环(也就是在平面图和对偶图中分别形成一颗树),边数加起来恰好是 。
对于本题,我们用两个 LCT 分别维护原图和对偶图的最小生成树和最大生成树,改变一个边权时,如果是变小,用原图的 LCT 判断生成树是否改变,如果变大,用对偶图的 LCT 判断。
时间复杂度 。
T3
题意就是一个矩阵树定理,它的基尔霍夫矩阵(的 阶主子式)是长这样的( 是给定的权值,)
就是一个 的矩阵,求 ,不过 。(但保证了 是 的次幂)
但这是一个循环矩阵,所以我们给它右乘一个范德蒙德矩阵(我数学菜,不知道怎么想到的,但乘完真的好神奇啊)
其中 是 次单位根。我们先令一个函数 。然后发现 是长这样的
发现 就是 在每列乘了 ,所以 ,又因为 ,所以我们要求的 就等于 。
直接 DFT 求出所有 即可,复杂度 ,好耶!
4.8
模拟赛直接摆烂,听完讲题 T2 直接弃
T1
给你长度为 的 01?
构成的串 。
求 串序列 的个数,要求:
- 是 的子序列
- 由 将每个
?
替换成0
或1
得到
模 ,。
先来牛逼的转化题意
先不考虑 ?
,从 到 就是把 每次删一个字符,不过如果两中删法得到的序列相同,那么算同一种方案,所以我们不妨钦定删 0
只能删连续一段 0
的最右面那个,删 1
只能删连续一段 1
的最左面那个,也就是说,相当于每次找到一个 01
然后删掉其中的 0
或 1
(再序列开头补一个 0
,结尾补一个 1
)。这样计数就不会重。
我们再每个两个位置中间加上分隔符,比如 101
变成 0A1B0C1D1
,每次选择其中⼀个 01
删除的时候, 我们也把分隔符删除。那么每个分割符被删除的时间就是一个 的排列,而 0
相当于它左面的分隔符先于右面被删,1
是右面先于左面。
把 0
换成 <
,1
换成 >
,计数满足条件的排列,据说这是一个经典问题。
表示考虑到第 个位置的方案,然后枚举前面 >
的位置容斥:
稍微变形:
现在它看起来就非常的卷积,于是分治 FFT 即可。
至于 ?
就是把序列分成若干段,每段分别计算,最后乘个组合数合并就行了。
时间复杂度 。
T3
有一个 个节点的树,你要从中选出若干条长度为 的简单路径(两两边不能相交,点可以相交)。求最大权值和。
。
首先肯定往 DP 方面想吧, 表示节点 的子树中,并且从 往下选了一条长度为 的链,的最大权值。答案就是 。
不过我们发现转移有些棘手,我们分别考虑 和 。
时,如果 的 我们就是要把 的 和 两两配对,然后剩下的选 (当然也可以不选),如果 就是选一个 从 转移上来,剩下同样这么配对。
配对的过程我们可以再搞个 DP, 表示考虑到第 个儿子,当前选的 和 的差值为 。记录一下前缀和后缀的 dp 值即可。
的情况类似,就是 和 配对,然后 之间也要两两配对,剩下的选 或不选。给 加一维 表示当先选的 的奇偶即可。
不过问题就是,这个 的 这一维大小是 ,这将导致总复杂度变成 。
但我们真的需要把这一维开到 吗?
我们把 的所有儿子顺序随机打乱,我们发现最优转移的情况就相当于随机一个 或 的序列,最后的和为 ,而这个随机 序列的前缀和最大值是低于 的。(这个好像有神仙证了),这意味着我们把 的 这维开到 算出正确答案的概率是及其大的。
于是,时间复杂度 。
4.9
T1 诈骗题,这不好。
T3 摆烂不看了,反正也没人过(好像数据锅了
T2
计数 个点的有向图,满足:
- 每个点的出度和入度都为 ,且不存在重边
- 对每个点 ,存在至多一个 ,不能连边 。
,模 。
就大力容斥呗 /cy
题意抽象一下就是, 对数填到 对位置上,其中每个位置有不能填的数,每对位置上的数不能相同,的方案数,不过因为每对位置两个数没有顺序,最终答案要除掉 。
先容斥掉 不能填的限制,我们先求出一个系数 表示序列中选出了 个位置填了对应的 ,且有 个位置中有 个位置上的数只钦定了一次。记 表示 在序列 中出现的次数,容易得到 dp
然后,我们设 表示 个单独的数, 对数,放入 个单独位置, 对位置的方案。那么最终答案就能写成
然后我们考虑求 ,注意此时 中 个单独位置依然是有限制的,不能填对应的 ,否则填的数就和原来和它一对的位置的数相同了。所以继续容斥
其中 和 含义类似,只不过单独位置上没有了限制。此时求 就容易很多了,若 考虑枚举其中一个单独位置放了哪个数,有以下递推
递推边界 ,剩下的位置都是成对的,相邻两个位置不能填相同的数,与是继续……容斥。
然后我们就做完了,发现对于 和 都有 ,所以状态数都是 的,按照上面的式子挨个算,总复杂度 。
4.11
T1
新听说了一个东西,积和式,不过这个东西没法多项式时间求,好像不是很有用。
不过这个题给的矩阵是一个下海森堡阵,积和式和行列式一样是可以拉普拉斯展开的。所以不断按第一行展开,就容易得到 递推求积和式和行列式的方法。
T2
,其中 是 的质因数分解。
求 ,。
首先这个数据范围看起来就非常 min25。
但是 不是积性函数欸!
再想想,我们有 ( 且 中不包含质因子 )。
所以就魔改一下 min25 的第二步求 就能做了(要同时筛 和 的和)
T3
有数列 ,然后给你 ,求 , 组数据。
。
首先记 ,找规律猜出结论,。
然后通过辗转相除将 消成 ,现在 。
先求 。为了求 ,我们考虑求 在模 下的值,这个是容易矩阵快速幂做的。
现在 。提出来一个 变成 ,跟上一步一样,计算 模 的值即可。
最终复杂度就是 。
4.12
T1
原
T2
维护一个集合 ,支持一下两个操作:
-
插入一个数 。
-
在 中选择一个数 , 中选择两个数 ,最小化 ,求这个最小值。
。
首先是经典结论,如果有 ,则有 。证明考虑 和 二进制下从高往低第一个不同的位即可。
所以我们发现,能作为答案的 一定是 中元素排序后相邻的数。然后我们再考虑什么样的 有可能作为答案,发现 作为答案的必要条件是:(或 )是 (或 )将二进制下为 的一位改成 ,它后面全改成 得到的。这样的 只有 个,于是能作为答案的 总共只有 对。
记 为 时的最小答案,我们用 set 维护所有可能作为答案的二元组 ,且 set 中只保留 且 的二元组(类似单调栈),这样就可以 的在 set 中二分查询答案了。
复杂度 。
T3
码了 8.1 K 的数据结构题,调代码十分心情愉快(斯德哥尔摩了属于是)
一张无向图,最开始图仅有一个 号节点。现在有 次操作,每次操作为以下 种之一(不妨假设每次操作前这张图的节点编号区间为 ):
-
删去 号节点,并删去 号节点连接的所有边。
-
删去 号节点,并删去 号节点连接的所有边。
-
增加 号节点,并连接 条边,第 条边连接 ,边有边权。
-
增加 号节点,并连接 条边,第 条边连接 ,边有边权。
-
对当前图询问最小生成树的边权和。
。
动态维护 MST 不是 LCT 吗,有删除?线段树分治好了,我会 暴力!很好,过了
正解的启发思路来源于一个部分分,前 次操作都是 ,此后保证 。
我们假设现在已经得到了 的最小生成树,要加入点 ,此时我们尝试加入边 ,只需知道 到 路径上的最大值即可,也就是说,我们感兴趣的只是 这些点两两路径上的最大值,于是我们把 的点当做关键点,求出其在 最小生成树上的虚树,虚树上的边权为其在原树上代表的路径的边权最大值,该虚树大小只有 ,但根据它我们完全可以求出加入 后的最小生成树!
于是我们得到了一下做法,左面加入一个点时,只维护此时 在最小生成树上构成的虚树(加上 是为了方便最后与右边的结果合并),考虑到有删除操作,把过程中得到的虚树全部用 的空间存下来即可。具体地,加入一个点以及其连接的 条边时,与原来的虚树上的所有边放到一起 kruskal 求出新的最小生成树,让后 dfs 求出新的虚树,这部分复杂度为 。右边的同理,询问时,只需把 的虚树和 的虚树放到一起跑 kruskal 即可,这样总复杂 ,我们就做完了这个部分分。
再考虑正解,我们发现其与正解的差别就是正解需要考虑到当前 长度可能小于 ,且 一直在变化不会一直包含 ,这个的解决方法却非常暴力,那就是定期重构。
设当前 为当前的中心区间,如果 或 ,我们就直接令 变成当前 的中间位置,然后重新计算加入 和 点的那些虚树。下面分析复杂度。
考虑势能分析,定义势能 ,插入操作回让 ,而重构操作会令 减半,重构的复杂度为 ,那么总的复杂度不会超过 。
还有就是如果当前 我们就直接 prim 暴力求解即可,复杂度是 ,所以最终的复杂度为 。不过实际的运行时间瓶颈显然不在这里,而在常数巨大的每次构建虚树。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!