2025.5 训练笔记
Week 1
P4695 [PA 2017] Banany
建出点分树,每个点 \(x\) 处维护子树内点的权值减去它到 \(x\) 的路径和,用线段树维护最大值,查询时到根每个点查最大值,注意去掉当前点,分成两个区间查询,不需要去重因为重复不优
修改边 \((u,v)\) 权值会发现在每层中改的是 dfs 序连续的一段,线段树上区间加减即可,要修改的层是 \(u,v\) 到根路径上的
查询点到当前点的距离可以在线段树上直接查出,复杂度 \(O(n\log^2 n)\)
CF1344E Train Tracks
每次切换相当于将一个点到根的链变为实链,路径上其它点其它边变成虚链,根据 lct 的理论,实边和虚边只会切换 \(O(n\log n)\) 次
每个点处发生的每次切换有一个最早时间和最晚时间,维护每次切换的时间区间,就能扫描线,每个时刻加入最早时间到了的切换,贪心切换最晚时间最早的,如果最晚时间晚于当前时间则发生冲突,此时最晚时间不早于它的都不必切换了
找出这些边,可以用启发式合并实现,在两个子树合并时找出交错的需要切换的时间
时间复杂度 \(O(n\log^2 n)\)
P7564 [JOISC 2021] ボディーガード (Day3)
每个人有坐标和时间两种状态,把它看成二维平面上的一个点 \((t,x)\),则一个人的起点是 \((t_i,a_i)\),终点是 \((t_i+|a_i-b_i|,b_i)\),平面上的路径长度是原来的 \(\sqrt 2\) 倍
人和保镖的行走方式都是斜率为 \(\pm 1\) 的直线,把坐标系逆时针旋转 45 度,\((x,y)\) 变成 \((x-y,x+y)\),路径长度变成原来的两倍,每个人的行走路径是水平向右或竖直向上的一条线段
保镖只要走到存在的线段上,每个单位就能获得覆盖那条线段最大的 \(\frac {c_i} 2\) 的收益,保镖每次只能向右或向上走
把所有 \(O(n)\) 个关键点横纵坐标拿出来离散化,可以 \(O(n^2)\) DP 求出保镖从每个点出发后能获得的最大收益
但每次保镖是从中间某个点出发,它能向上或向右走到线段上,再走到旁边的关键点,在线段上的贡献是 \(\frac {c_i}2\times x+val\),是一次函数的形式,可以用李超树维护,时间复杂度 \(O((n^2+q)\log n)\),可以通过,维护凸包可以做到 \(O(n^2 + q\log n)\)
P7563 [JOISC 2021] 最悪の記者 4 (Worst Reporter 4) (Day4)
\(i\) 向 \(a_i\) 连边,图形成内向基环森林,每条边指向的点的权值要小于等于另一端,环上的点权值必须相同
现在就转化成树的情况,朴素的 DP 是设 \(f_{i,j}\) 为第 \(i\) 个点权值为 \(j\) 的最小代价,离散化权值后可以做到 \(O(n^2)\)
发现 \(f_{i,j}\) 固定 \(i\) 时随 \(j\) 增大单调不降,转移每次就是对位相加,可以线段树合并维护,修改当前点的权值就是区间加,然后需要将前面的与 \(f_{x,a_x}\) 的值取 \(\min\),由于只需要全局最小值,可以打标记维护,标记顺序先取 \(\min\) 后加
环上的处理就照常区间加后把环上每棵线段树合并即可,时间复杂度为 \(O(n\log n)\)
P7220 [JOISC 2020] 掃除
从特殊性质入手,如果每个点从左到右下降,那么每次修改是一个区间,区间推平即可
发现每个点在第一次推平后就满足这个性质了,可以从后往前,每个操作单点修改,区间查询找到每个点第一次被推平的操作,但现在还不支持动态加入点
使用线段树分治,把每个点的存在区间拆成 \(O(\log q)\) 区间,从左往右处理,每个区间处理 \(r-l+1\) 个推平操作,但要支持中间插入一个点,区间推平,用平衡树维护,复杂度 \(O(n\log^2 q)\)
LOJ3628「2021 集训队互测」树上的孤独
如果只有第二棵树,查询 \(x\) 子树内距离 \(x\) 不超过 \(d\) 的点的颜色数,启发式合并,维护每个颜色出现的最浅深度,在这里有 \(1\) 的贡献,查询前缀和即可,强制在线可以主席树维护
加入第一棵树,由于点数很少,只需要知道每个在第一棵树中出现的颜色是否已经在第二棵树的范围中出现了,由于只加密了深度,这个可以离线查询,把第一棵树中所有颜色都查询出它在第二棵树中 \(x\) 子树内出现的最浅深度,可以启发式合并做到 \(O(qn)\)
总时间复杂度 \(O(qn+m\log n)\)
QOJ7513 Palindromic Beads
每对颜色在路径上距离从大到小,所以可以把所有颜色按两个点距离从远到近排序,用 dfs 序转化成单点修改,矩形取 \(\max\),可以树套树维护做到 \(O(n\log^2 n)\)
但有更巧妙的做法,dfs 时考虑点 \(x\),设 \(f_x\) 表示颜色 \(x\) 为最外层的颜色时的最多选择点数,若它做为当前路径上点的最外层,则其它颜色某个点在它到根的路径上,另一个点在它的另一个点到根的路径上,每个颜色的两个点如果有祖先关系则在深度更深的点查询和加入
于是每个 \(f_{x}\) 对其它颜色的贡献是另一个点的子树内的,区间取最大值,用主席树维护,注意有些细节,每个点继承它父节点的树,查询单点值,时空复杂度均为 \(O(n\log n)\)
QOJ7341 A Text Problem
把 \(s\) 正反串都建出 SAM,询问串从正反两端开始在对应 SAM 上跑,每个点有在 SAM 上对应的节点,枚举不同的位置 \(i\),它前面和后面在 SAM 上均有对应节点,如果把正串 SAM 的 endpos 加一,反串 SAM 的 endpos 减一,此时要求的是两个节点 endpos 集合内交集的数量
把每个终止节点在两个 parent tree 上 dfs 序找出看成坐标 \((x,y)\),则每次求的是矩形内的点数,可以离线扫描线求出
最后答案则是所有不同位置贡献之和减去 \(n-1\) 倍原串出现次数,复杂度 \(O(m\log m)\)
LOJ577「LibreOJ NOI Round #2」简单算术
把多项式强行拆开
由于 \(p\) 很小,看到这种多重组合数就想到 Lucas 定理带来的经典结论,若值模 \(p\) 意义下不为 \(0\) 则 \(m\) 写成 \(p\) 进制数后每一位都恰好分到 \(n+1\) 个 \(c_i\) 上,不发生进位
于是可以把贡献按位拆开,组合数的方案就是每位选择的方案相乘,而 \(a_i^{c_i\times p^x}\) 可以用欧拉定理,就等于 \(a_i^{c_i\times p^x\bmod p-1}=a_i^{c_i}\)
所以现在每一位都相同了,预处理 \(f_{i,j,k}\) 表示前 \(i\) 个数,每个数 \(<p\),和是 \(j\),\(\sum_{i=0}^n ic_i=k\) 时的总贡献,转移枚举下一个数是多少,\(k<(n+1)p\),总复杂度 \(O(n^2p^3)\)
询问时则处理 \(k\) 和 \(m\) 在 \(p\) 进制下的每一位,按位 DP,设 \(g_{i,j}\) 表示第 \(i\) 位,向下一位 \(k\) 的进位是 \(j\) 的方案数,每一位和要跟 \(m\) 相同,进位后这一位要和 \(k\) 相同,由于每一位对 \(k\) 的贡献最多 \((n+1)p\),\(j\) 这一位大小是 \(O(n)\),且由于进位后对位相同,每次枚举下一位的枚举量只有 \(O(n)\),这部分复杂度 \(O(\log_p^m n^2)\)
总复杂度 \(O(n^2p^3+T\log_p^m n^2)\)
UOJ424 【集训队作业2018】count
考虑建出序列的笛卡尔树,规定数值相同时更靠前的更大,则序列等价当前仅当它们的笛卡尔树相同,只需要计数笛卡尔树的数量
而且发现用不同元素是优的,因为这样区分大小关系时就没有位置的限制,当 \(n\ge m\) 时任何一棵笛卡尔树一定可以把 \(m\) 个数都用到,每个数都出现的限制也没有了
但不是所有二叉树都可以是笛卡尔树,因为数只有 \(m\) 种,若出现了点数为 \(x\) 的向左的链,则至少需要 \(x\) 种数,限制相当于二叉树最长的向左的链点数长度 \(\le m\)
因为 \(n\) 个点无标号有根二叉树的数量为 \(Cat_n\),于是猜想这是类似于括号序列前缀和 \(\le m\) 之类的双射,有把二叉树转为多叉树的思考方式
但可以把 \(n\) 个点二叉树看成与 \(n+1\) 个元素,\(n\) 个符号的后缀表达式形成双射,因为去掉第一个元素后,每个前缀元素数量大于等于符号数,然后向左向右链是对称的,限制看成向右链长度 \(\le m\),转化到后缀表达式上就是去掉第一个元素后每个前缀元素数量减去符号数量 \(\le m\)
这就是经典的问题了,交替翻折容斥解决,复杂度 \(O(n)\)
5.5 模拟赛
A. 多米诺
猜测方案数 \(f(H,W)\) 为关于 \(H,W\) 二元均是 \(n\) 次的多项式,分开插值,对 \(n+1\) 个第一维点值每个求出 \(n+1\) 个第二维不同的值,做一次插值能求出当第二维是 \(W\) 时这 \(n+1\) 个第一维的值,再一次插值即可求出 \(f(H,W)\)
求出两位都是 \(2n\) 以内的方案数可以插头 DP,总复杂度 \(O(2^{2n}n^3+n^3)\)
B. 抽奖机
首先至多只会从两个机器中抽,因为目标球只有两个,其它机器中抽的都无关,那么策略是要么从一个机器中一直抽,要么抽到一定程度后从另一台机器中抽出其中一个颜色
从一个机器中一直抽的最坏步数显然是颜色数加一,关键在于从两个机器中抽的步数
如果从一个机器中抽出了颜色集合 \(S\),那么另一个机器的目标是抽出 \(S\) 中的一个颜色,此时另外的每个机器最坏情况下不会先出现抽了两个相同颜色,所以步数是它的颜色数减去与 \(S\) 的交集大小再加一,而如果想再在原来机子里抽让交集增加 \(1\) 时,另外的机器步数最多减少一,但此时已经至少多抽一个了,不优
所以只需要考虑交集是 \(1\) 的情况,此时另外的机器中抽的步数就是颜色数,还能得到推论时第二台机器中无重复颜色,否则此时再从它中抽一个就一定满足了
每种颜色的权值定义为含有它的其它机器中颜色数的最小值,于是第一台机器中的最坏情况就是颜色按权值从大到小抽出,排序后取步数最小的即可,复杂度 \(O(n\log n)\)
赛时想错了,以为其它机器中抽的步数和交集中球的个数有关而推不出交集为 \(1\) 的结论,想错的原因是没注意第二台机器也要保证抽出的颜色不同
C. 树
\(n\) 个叶子的满二叉树的数量是 \(Cat_{n-1}\),把向左的边看成左括号,向右的边看成右括号,则 \(2(n-1)\) 条边组成的一定是合法括号序列,因为前缀左括号的数量不少于右括号
那么虚树中没有 \(m\) 偏树,相当于前缀左括号减右括号数量 \(<m\),转化为经典容斥问题,时间复杂度 \(O(n)\)
5.7 模拟赛
A. [ARC115F] Migration
啥心理阴暗组题人把 ARC F 放 T1,更搞笑的是后面 T2 还是个依托构造题
二分答案,起始终止状态可以都走在中间相遇,那么如果此时起始状态能到终止状态则它们能到的势能最小状态相同
每个点想办法往势能更小的点走,每次走到势能更小且路径中最大值最小的点,则每个点下一次到的点是固定的,可以用类似 Kruskal 重构树的方法 \(O(n\log n)\) 求出
由于每次移动后总势能减小,所以优先移动最大值更小的
所有点向下一个点连边,则形成内向基环森林,且深度更浅的边最大值更大,因此所有移动都是从深到浅,一次移动一个节点上所有棋子,只会移动 \(O(n)\) 次
判断两个状态是否相同可以给每颗棋子赋随机权值,每个点的权值是点上棋子权值的异或和,判断每个点两个状态下的权值是否相同即可
实现起来其实每次选两个状态增量更少的一个走,不需要二分,但二分后再做会更方便,时间复杂度 \(O(n\log V)\)
C. 矩阵
建二分图最大匹配的图,黑点一边,白点一边,两个点若横纵坐标有一个重合则连边
最大匹配等于总点数减去最大独立集,而独立集形如选行集合 \(R\),列集合 \(C\),设 \(S(R,C)\) 为横纵坐标均在 \(R,C\) 中的点,则 \(S(R,C)\) 中点为同色,\(S(\overline{R},\overline{C})\) 中点为另一种颜色
设 \(s(R,C)\) 为横纵坐标均在 \(R,C\) 中的黑点数,最大独立集大小为 \(|R||C|-s(R,C)+s(\overline{R},\overline{C})=|R||C|+s(U,U)-s(R,U)-s(U,C)\)
设一行、一列的黑点数分别为 \(a_i,b_i\)
让式子的值尽量大,把行、列按黑点数量从小到大排序,选的一定是一个前缀,如果确定了行数 \(|R|\),那么选一列的贡献是 \(|R|-b_j\),取这个值大于零的那些列即可
求出初始答案后,修改只会对 \(a_i,b_i\) 加一或减一,经典的处理方式是挪一下修改位置使得数列不用重新排序,每次修改会对每种行数答案的一个后缀产生影响,线段树维护每种 \(|R|\) 对应的值,区间加减求全局最大值即可,时间复杂度 \(O((n+q)\log n)\)
5.9 模拟赛
A. P3274 [SCOI2011] 植物大战僵尸
啥心理阴暗组题人把这种特别难写题放 T1,更搞笑的是题解中原来的 T3 也是个码量不小的数据结构题
先从下往上扫描每个漩涡,找到分别从两个方向离开它后下一次到达哪个漩涡及会从哪个方向离开它,可以记录当前每条斜线最靠上的漩涡,如果对应斜线没有漩涡则从两侧反弹,不难发现这里暴力反弹时间复杂度关于行数线性
把每个漩涡拆成两个点代表两个出发方向,连边后图是若干条链
每次删除一个漩涡后,如果它不在边上,那么走到它后方向不会变化,即它的两个点的出边交换了,在链上就是两段链交换
用平衡树维护这些链,每次删除漩涡可以用平衡树的分裂合并完成
最麻烦的部分是统计答案,对每列不好维护以它起始的答案,转而维护每棵平衡树上横坐标最小的可以作为出发点的点,则这棵平衡树对答案的贡献是这个点及它后面的点数,每次删除后要更新可能作为出发点的点,每次找到贡献最大的平衡树
把所有平衡树的贡献塞入堆中,注意要先删除被修改到的平衡树,再修改,再加入它们新的贡献,写起来细节非常多, 复杂度 \(O(n\log n)\)
B. 变换
这也太神秘了
由于串是无限的,所以可以看作每个位置和它后面的 \(2k\) 个位置有关,就能从左到右依次推出位置,每次会给 \(1\) 的数量带来不超过 \(1\) 的变化量,记录当前 \(1\) 的个数和原来个数的差 \(c\)
记录 \(2k\) 个数状态为 \(s\),则每一步相当于连了一条 \(s\to t\) 的有向边,边权为 \(-1/0/1\),\(p\) 合法相当于从 \(0\) 出发在图上任意走最后回到 \(0\) 的路径的边权和都为 \(0\)
由于图强连通(显然从一个状态若干步后肯定可以到另一个状态),则相当于图中所有环边权和为 \(0\),把所有反向边加入,此时图合法的充要条件是图没有负环,否则说明原来有正环或负环
\(p\) 的每一位恰好对应一条边,朴素的方法是暴力枚举 \(p\) 然后判断
枚举第一个比 \(p\) 大的位,这相当于 \(p\) 的一个前缀固定,后面任取,设 \(0\) 到 \(s\) 的距离是 \(d_s\)
- 如果 \(s\to t\) 边权是 \(1\),则反向边 \(t\to s\) 边权是 \(-1\),那么 \(d_s+1\ge d_t,d_t-1\ge d_s\),则 \(d_t=d_s+1\)
- 如果 \(s\to t\) 边权是 \(0\),则反向边 \(t\to s\) 边权是 \(0\),那么 \(d_t=d_s\)
- 如果 \(s\to t\) 边权是 \(-1\),则反向边 \(t\to s\) 边权是 \(1\),那么 \(d_s-1\ge d_t,d_t+1\ge d_s\),则 \(d_t=d_s-1\)
对于已经固定的位直接连边就行,没固定的位每个可以在 \(\{0,1\}\) 或 \(\{0,-1\}\) 中选一个,则 \(d_t\) 关于 \(d_s\) 的取值是一个范围,可以用差分约束建图,如果边权 \(\in\{0,1\}\),则连 \((s\to t,1)\),\((t\to s,0)\),差分约束有解说明 \(d_s\) 的分配存在,即原图没有负环,复杂度 \(O(2^{3(2k+1)})\)
复杂度瓶颈现在在 SPFA 找负环上,由于有反向边,如果一个点被更新 \(3\) 次,那么最短路至少减少了 \(2\),沿原来的路走回去一定有负环,所以 SPFA 的复杂度是 \(O(m)\),总复杂度 \(O(2^{2(2k+1)})\)
C. QOJ6537 One, Two, Three
非常神秘的推性质
假设固定了 \((1,2,3)\) 的数量是 \(a\),\((3,2,1)\) 的数量为 \(b\),对于 \((1,2,3)\) 内部,所有组按 \(1\) 的位置从小到大排序后,\(2,3\) 的位置也是从小到大的,容易通过调整法说明所有方案调整成这样不劣,对于 \((3,2,1)\) 同理
对于 \(1\) 的所有出现,它的一个前缀贡献给 \((1,2,3)\),后缀贡献给 \((3,2,1)\),对于 \(3\) 则反过来,再根据上面的结论每个 \(1\) 对应的 \(3\) 确定了,现在要尽可能让 \(2\) 匹配 \(1,3\) 对,把一对看成起止点在两个数的一条线段
对每个 \(2\) 可以匹配把它夹在中间的 \(1,3\) 对,如果双指针枚举了 \(a,b\),可以贪心,将所有形成的线段在左端点加入,对每个 \(2\) 优先匹配能匹配的线段中右端点更小的,复杂度 \(O(n^2\log n)\)
把 \(2\) 当左部点建出二分图,如果合法则图有右部点的满匹配
使用 Hall 定理,每次只用考虑一个区间内的线段,设 \(f(l,r)\) 为 \([l,r)\) 内完全包含的线段数,\(X_i\) 为 \([0,i)\) 中 \(X\) 的个数,注意到每个 \(1,3\) 形成的线段互不包含,那么 \(f(l,r)=\max(0,a-1_l-(3_n-3_r))+\max(b-3_l-(1_n-1_r),0)\)
所以 \(|S|\le |N(S)|\),\(\max(0,a-1_l-(3_n-3_r))+\max(b-3_l-(1_n-1_r),0)\le 2_r-2_l\),把 \(\max\) 拆开得到 \(4\) 个不等式,它们都要满足,将 \(a,b\) 放到不等号小的一边,推式子能发现 \(l,r\) 可以分离,能对每个 \(r\) 求出它前面使得值最大的 \(l\),进而求出全局的最小值,得到 \(a\le x,b\le y, a+b\le z\) 的限制,就能求出 \(a+b\) 的最大值和 \(a,b\) 分别是什么
最后构造方案就用前面的贪心方法构造即可,复杂度 \(O(n\log n)\)
Week 2
5.12 模拟赛
C. tree
P9340 [JOISC 2023] Tourism (Day3) 的加强版
题意是求区间内所有子区间权值和,一个子区间的权值是范围内点形成的虚树的边数
一条边有贡献说明区间内的所有点不都在靠下的点的子树内也不都在子树外,不好处理,做容斥,有点在子树内就算,这样一个区间恰好会多算区间的 lca 到根的距离,最后减掉就行
考虑每条边的贡献,将树重链剖分后启发式合并,将轻子树的点插入重子树,用 set 维护每个子树内的点,假设区间跨过 \(x\),此时贡献是每个左端点在 \([pre_x+1,x]\),右端点在 \([x,n]\) 的区间
合并一个点会带来一些区间的终止和新增,但是重子树内那些没有被修改过的区间依然有贡献,不能暴力遍历
对每个区间加入时记录它的加入持续时长,处理一条边时持续时长为它到所在重链顶的边数,每次终止区间时扣除还剩余的加入时长即可
对于原题,离线所有区间后变为矩形加单点查询,扫描线维护即可,对于加强后的题意要套上区间加求区间历史版本和的板子
复杂度 \(O(n\log^2n)\)
5.13 模拟赛
A. easy
明明这太人类智慧了吧!
一行一行从上往下考虑找不到很好的规律,考虑转化视角,一列一列考虑,则每一列都可以选择去掉或不去掉最上面的一个格子
尽量竖着摆放减少对后续的影响,但如果这一列空余格子是奇数,那么必须新增一个横着摆放的格子,它延伸到下一列,否则当前列如果有横着伸过来的,就能去掉一个限制
由于每次最多去掉一个格子,那么去或不去我们不关心它们具体对应哪个奇偶性,反正它们奇偶性不同,问题就可以抽象成初始 \(y=0\),每次可以选择 \(y\gets y+1(y<n)\) 或 \(y\gets \max(0,y-1)\),求 \(m\) 次操作后最终 \(y=0\) 的方案数,可以 \(O(nm)\) DP
把它刻画成行走,从 \((0,0)\) 出发,每次可以斜着往右上,右下走一步,但不能越过 \(y=n\),当 \(y=0\) 时不能往右下只能平着走一步,问到达 \((m,0)\) 的方案数
这和经典的反射容斥有些差别,但很智慧的想法是我们把整张图沿 \(y=-0.5\) 对称,\(y=n+1\) 对称至 \(y=-2-n\),从 \(y=0\) 处向右下走一步后 \(y=-1\),刚好对称回去就是 \(y=0\)
把一条从 \((0,0)\) 出发到达 \((m,-(m\bmod 2))\) 且不碰到直线 \(y=n+1\) 和 \(y=-2-n\) 的路径想象画在纸上,让纸沿着 \(y=-0.5\) 对折,发现所有这样的路径刚好和原来的合法路径一一对应,即形成双射
于是统计这样的路径就好了,是经典的反射容斥,复杂度 \(O(n)\)
B. cactus
考虑树的情况,发现每个点会不会用到它连向父节点的边是确定的,直接 DP,注意 \(2n\) 条边两两配对的不同方案数是 \(n!!\)
对仙人掌建出圆方树,但发现一个点上可以连很多个环,那么每个环可以拿出与它相邻的 \(1/2\) 条边打散匹配
在方点处,它的子节点为对应环上的所有点去掉它父节点,按顺序 DP,每个点有可能需要环上的 \(0/1/2\) 条边来和它匹配,设 \(g(i,0/1)\) 表示 \(i\) 后面的一条边是否已经被使用的方案数,讨论这条边是和环上前面/后面组成匹配还是和当前点需要的连边形成匹配,最后根据子树内边数的奇偶性,决定只剩下一条边还是 \(0/2\) 条边,剩下的边一定和父节点相邻
在圆点处,它子节点的方点剩下了 \(0/1/2\) 条边,用分治做多项式乘法做背包合并,得出它这里要合并 \(i\) 条边的方案数,再讨论它还需要的边数,乘上对应的权值即可
时间复杂度 \(O(n\log^2 n)\),瓶颈在分治 NTT,代码怎么这么难写啊(
C. string
如果 \(TP=PT\),说明 \(P,T\) 拥有相同的最小循环节,而 \(TP\not\in S\),则此时不合法的 \(T\) 即是对于 \(S\) 中一个连续出现了 \(\ge 2\) 次的子串,它非最大的循环次数形成的串
如果会 runs 发现这几乎是它的模板,注意去掉本质相同串即可
但我们不会,考虑使用 优秀的拆分 做,枚举循环节长度 \(len\),隔 \(len\) 放置关键点,把长度为 \(len\) 的分成一块,发现一个循环节跨过一个关键点,且循环多次的串中间的每块相同,双指针求出极大的相同块段,求出段首尾散块与中间块的 LCP、LCS,此时枚举串长 \(k\times len\),它的首尾必须在指定区间内,存下这个长度的串开头可能所在的区间
这部分时间复杂度为调和级数 \(O(n\ln n)\)
但是还要去掉本质相同的串,考虑后缀数组,以一个位置开头的所有串只计入后缀数组上排序后与前一个不是公共部分的串,对每种长度从小到大处理,每次加入一些在此时合法的开头,然后查询这个长度的串开头位置区间的并中的合法开头总数,可以用树状数组维护,复杂度 \(O(n\log^2n)\)
Week 4
5.20 模拟赛
B. P9084 [PA 2018] Skwarki
从最大值开始考虑,最大值不会被删除,两边互不影响,可以看作是序列一段有一个极大值在不断让两头被删除
于是考虑 DP,枚举最大值所在位置,设 \(f(i,j,0/1/2)\) 表示长度为 \(i\) 的序列,两端没有/有一个/有两个极大值,在第 \(j\) 次操作后还剩 \(\ge 1\) 个数,\(j+1\) 次后全部删空(两端无极大值 \(j\) 次操作后只能剩一个)的方案数
转移则枚举当前最大值位置,把序列分成两半,讨论两边各剩下几次,注意边界,用前缀和优化
时间复杂度 \(O(n^2k)\),但注意到序列每次最多留一半,因此最多进行 \(O(\log n)\) 轮,时间复杂度 \(O(n^2\log n)\)
5.23 模拟赛
B. 取石子游戏
唉博弈论猜结论猜不出来,没有注意力(
首先每种颜色是单独的子游戏,可以分开算出 SG 值后合并,因此现在假设全都是一种颜色
如果每堆石子数都 \(\le m\),那么在一堆中能任意取的条件没用,根据经典结论 SG 值是总和 \(\bmod (m+1)\)
但是现在一堆石子中可以任取,要想改变原来的局面,一堆中肯定取 \(m+1\) 的倍数,顺便也可以更改余数,这样把 \(m+1\) 个视为一个整体,跟普通 nim 游戏很类似了
所以 SG 值跟每堆石子的数量除以 \(m+1\) 的值和总和 \(\bmod (m+1)\) 的余数有关,而且前一项优先级更高,猜测 SG 值是 \(\bigoplus_{i=1}^n \lfloor\dfrac {a_i}{m+1}\rfloor+(\sum_{i=1}^n a_i)\bmod (m+1)\),可以归纳验证,但怎么想到的???
后面就是经典的内容,\(m\) 很小,设 \(f_{i,j,k}\) 表示前 \(i\) 个数和 \(\bmod(m+1)\) 为 \(j\),异或和为 \(k\) 的方案数,第三维的转移能用 FWT 优化,第二维是循环卷积,可以暴力做,最后每种颜色用 FWT 合并即可
时间复杂度 \(O(n(m^2\frac V m+V\log V))=O(nV(m+\log V))\)
5.24 模拟赛
B. QOJ10045 Permutation Recovery
考虑一组排列和逆排列,连出置换环后它们的方向相反,因此若第 \(i\) 列有 \(j\),第 \(j\) 列也有 \(i\)
把这样两两配对的找出来,包括相同的,如果配对失败则无解
目标是把这样的 \(i,j\) 对确定方向后组成若干置换环,把 \(n\) 个值每个看成一个点,若有 \(i,j\) 配对则连它们之间的无向边,则每个点度数均为 \(2k\)
所以图中一定有欧拉回路,找出欧拉回路,就能对每条边定向,每个点刚好入度出度均为 \(k\)
现在要把回路拆成若干排列,每个排列中每个点入度出度刚好各一个,把每个点拆成两个点,入点和出点,\(u\to v\) 的边连 \(u_{out}\to v_{in}\),这是 \(k\) 正则二分图,一定能找到 \(k\) 组完美匹配,每组完美匹配就对应了一个排列
直接跑 \(k\) 次网络流复杂度为 \(O(n^{1.5}k^2)\),常数较小,也可以用 \(k\) 正则二分图边染色,当 \(k\) 为奇数时找一组匹配,否则跑欧拉回路隔一条边选一个,递归到 \(\frac k 2\),复杂度 \(O(nk\log k\log n)\)
Week 5
好像是 JS 省集的模拟赛,但怎么这么难啊,能放一点是题的东西吗(
5.26 模拟赛
这也太难了……
A. 生活美好没烦恼
不会多项式科技啊
考虑每个元素对答案的贡献,如果钦定最后留下第 \(i\) 个,那么它两端的序列相对独立,看作是一轮轮删除元素求总共的方案数,只不过每个序列必须留下开头
设 \(f_i\) 为长度为 \(i\) 的序列最后留下开头的方案数,答案是 \(\sum_{i=1}^n f_if_{n-i+1}a_i\)
考虑计算 \(f_n\),枚举第一轮留下 \(i\) 个数,要求这 \(i\) 个数中有第一个数且不能相邻,先去掉前两个,剩下 \(n-2\) 个数中选 \(i-1\) 个不相邻的数,相当于先去掉 \(i-2\) 个中间的数后任选 \(i-1\) 个,有递推式 \(f_n=\sum _{i=1}^{\frac n 2}f_i{n-i\choose i-1}\)
这是半在线卷积,但 \(f_{2n}\) 只有 \(f_1\sim f_n\) 贡献给它,考虑倍增计算,每次只算 \(f_1\sim f_n\) 对 \(f_{n+1}\sim f_{2n}\) 的贡献
组合数用高维前缀和体现(高维前缀和中的每个数对后面数的贡献次数可以类似格路计数计算),\(f_i\) 对 \(f_x\) 的贡献是将 \(f_i\) 放在 \(2i-1\) 的位置做 \(i\) 次前缀和后的第 \(x\) 个位置的数
考虑生成函数,做 \(k\) 次前缀和相当于乘上 \((1+x+x^2+\dots)^k=(1-x)^{-k}\),做 \(k\) 次差分是它的逆变换,相当于乘上 \((1-x)^k\)
前缀和是能一起做的,问题被转化成了倒着考虑,每次加上 \(F_i(x)=f_ix^{2i-1}\) 后乘上 \((1-x)^{-1}\),但实际上前缀和乘的生成函数次数太高,每次乘的次数必须到 \(n\),总次数没有保障,也不好做
转化为差分,先求 \(n-i\) 次差分后最后一起做 \(n\) 次前缀和,这样正着考虑,每次加上 \(F_i(x)\) 后只用乘 \((1-x)\),直接分治计算多项式卷积即可
最外面虽然有倍增,但序列总长度还是相当于 \(O(n)\),总复杂度 \(O(n\log^2 n)\),NTT 需要预处理单位根的优化
B. 最棒题目人人赞叹你
好像 std 被爆了
要找的是这几条直线取左侧后形成的半平面交最低点,朴素方法是用 \(O(n\log n)\) 次操作 2 将直线按斜率从小到大排序,求半平面交,求的方法是用栈维护已经在半平面交中的直线,将当前直线和栈顶求交点,如果交点横坐标比栈顶和栈顶后一个的交点横坐标还小则弹出栈顶,最后二分找出半平面交中斜率正负交界处两条直线,只需要用 \(\log n\) 次操作 1,它们的交点横坐标就是答案
这样瓶颈在排序,我们优化一下,\(n\) 次操作 2 找到斜率更小的直线,将其它直线按与这条直线的交点横坐标从小到大排序,这样就算出现斜率更小的直线排在后面,那么它一定是不在半平面交内的,所以判断当前直线和半平面交中最后一条直线的斜率大小,如果比它小则直接跳过
精细实现求半平面交的过程刚好可以再花 \(3n\) 次操作 2,操作 2 总共花 \(4n\) 次,操作 1 总共花 \(O(\log n)\) 次
5.27 模拟赛
B. toptree
原题是 UOJ841 龙门探宝,官方题解很清楚,懒得写题解了
C. 沙滩
用了一个叫 Kameda's Algorithm 的神秘定理,描述平面图 DAG 的可达性,使用要求是建超级源点 \(S\) 连所有入度为 \(0\) 的点,超级汇点 \(T\) 连所有出度为 \(0\) 的点,之后图依然是平面图且 \(S,T\) 在同一个面内
将所有点的出边按顺时针排序,先从 \(S\) 出发,每个点按顺序遍历出边 dfs,记录出栈序 \(dfn1_x\),然后第二遍 dfs 反向遍历出边,得到另一个出栈序 \(dfn2_x\)
如果 \(x\) 可达 \(y\),那么当且仅当 \(dfn1_x<dfn1_y\) 且 \(dfn2_x<dfn2_y\)
这个题就设 \(f_i\) 表示到 \(i\) 的最大价值,转移是二维偏序,按 \(dfn1_x\) 排序后树状数组维护最大值,方案用主席树维护,注意到一个数只会插入一次,可以直接比对主席树的节点
5.28 模拟赛
B. 树上游戏
典题不会,咋整?
先点分治,目标是处理两端点都在点集中的所有路径对点集中每个点的贡献,且去掉跨过分治中心路径
如果路径两端点都在根的同一子树,那么子树内的贡献分治计算,对点 \(i\) 的贡献可以看作 \(dis(x,root)+dis(y,root)+2dis(i,root)\)
如果路径两端点在不同子树,它们对其它子树中点的贡献形式相同,这部分的计算可以把权值 \(dis(x,root)+dis(y,root)\) 从大到小排序,对每个子树暴力找出两端点都不在子树中路径权值的最大值,用它更新子树内所有点的答案
对某一端点所在的子树,设 \(x\) 在子树内 \(y\) 不在,把路径拆成 \(x\to root \to y\),子树内每个点 \(i\) 会用 \(dis(i,x)+dis(i,root)+dis(root,y)\) 更新答案,把 \(dis(root,y)\) 看成挂在 \(x\) 上的点权,求出子树端点带权的直径即可,这部分全局先预处理 lca 可以做到 \(O(n\log n)\)
时间复杂度 \(O(n\log^2n)\),瓶颈在排序
C. QOJ1170 Hotspot-2
神秘性质题
把问题看成要求 \(\forall i,x_i+x_{i+1}\le a_i,x_i\ge 0\),最大化 \(\sum_{i=1}^n x_i^2\)
如果有中间一个大圆夹着两个小圆,则把较小的圆调整为一个点,扩大大圆一定不劣
所以以半径为 \(0\) 的圆为分界点,中间的段是单谷的
把单谷的看成向前/向后能扩展一段半径递减的圆,那么这一段空隙大小一定是递减的,且开头左/右侧的空隙更大
枚举起点,扩展出极长的段,那么这个段中的圆的可能半径都能计算,有了上面空隙的条件后发现段长总和是 \(O(n)\) 的
于是所有圆可以选择的半径总数是 \(O(n)\) 的,离散化出现的坐标,问题就变成了选出最多不相交的线段(同一个圆代表的线段都在圆心处相交了),直接 DP 就好了,时间复杂度 \(O(n\log n)\)
5.30 模拟赛
B. DFS 模板题
不带修的版本是 QOJ2708 Through Another Maze Darkly
把连向父节点的边看成最后一条,每个点在指针指向它是返回,但之后指针就会指向第一个点,下一次访问它时就能遍历它所有子树
记从根节点出发后走回到根节点为一轮,把每条边拆成往子树走和往祖先走两条有向边,每一步能走一条边
所以每条边只有第一次被访问的轮数是重要的,设第 \(i\) 条边第一次被访问到的轮数是 \(a_i\),之后每一轮都能访问到这条边
而且产生第一次访问的轮数最多为 \(n\),意味着后面的轮数都会按顺序访问每条边
当前点在 \(x\),发现初始时顺序在往祖先走的边之后的边会比进入 \(x\) 的边晚一轮访问,因此初始可以 dfs 推出每条边的访问时间
查询时间 \(t\) 时先二分它是在第几轮,判断则是求 \(\le x\) 的 \(a_i\) 的 \(x-a_i+1\) 之和,然后能求出它是第 \(x\) 轮的第 \(y\) 个,接下来二分具体的位置,判断是求下标 \(i\le y\) 的 \(a_i\) 中 \(\le x\) 的数的个数
考虑带修,记录每条边的 dfs 序(相当于除根节点的每个点欧拉序),发现变动初始值带来的影响就是对欧拉序一个区间的边进行 \(+1/-1\),目标是维护 \(a\) 数组的相关信息,即能快速求 \(\le x\) 的 \(a_i\) 个数与和
序列分块,由于访问顺序相邻的边 \(a_i\) 相差不超过 \(1\),那么每块内的值域是 \(O(B)\) 的,块内直接预处理前缀和,修改时整块打标记散块重构,能做到 \(O(B+\frac n B)\),查询一次可以做到 \(O(1)\)
总时间复杂度为 \(O(q(B+\frac n B\log n))\),取 \(B=\sqrt{n\log n}\) 能平衡复杂度至 \(O(q\sqrt{n\log n})\)
5.31 模拟赛
A. 最长路径
正解构造太精妙了,考验乱搞能力的时候到了
正解是考虑每次怎么把最长路折半,先求出每个点开始的最长路 \(f_i\),把点分为 \(d\) 层
然后按层建出类似线段树的结构,把所有边 \(u\to v\) 挂到 \(f_u, f_v\) 对应叶子节点在线段树上的 lca 处,发现此时删除线段树上一层的所有边,会让最长路长度至少除以 \(2\)
因此只需要删除边数最少的 \(\log d-\log l\) 层,这时删除的边数不超过 \(\frac{\log d-\log l}{\log d}m\)
场上能得到 80 分的乱搞是考虑当前拓扑排序,到 \(x\) 时若以 \(x\) 结尾的最长路 \(f_x\) 刚好是 \(l\),那么它要么删掉它的所有出边,要么删除一些入边使得最长路减少,删的那些 \(y\to x\) 的边肯定是 \(f_y\) 最大的一些
乱搞的地方在于选择,考虑算平均让 \(f_x\) 减少 \(1\) 需要的边数,就是删除的边数除以 \(f_x\) 的减少量,求出这个平均需要边数最小的方案,删掉这些边
B. 直线交点
求出 \([l,r)\) 的交点个数,把每条直线分别按在 \(l,r\) 处的纵坐标排序,找出两组顺序的逆序对即可,注意 \(r\) 处排序纵坐标相同的要按 \(l\) 处的顺序排序
于是可以二分答案,求出 \([l,mid)\) 内的交点个数
但是题目要求输出分数,可以实数二分然后还原为分数,但值域很大,精度误差太大导致只能获得 70 分
一种方法是在 Stern-Brocot tree 上二分分数,但复杂度为 \(O(n\log^3n)\)
这种时候可以考虑随机二分,每次不用取区间中点,随便取一个横坐标在区间内的交点作为分界点,复杂度可以考虑每次随机有至少 \(\frac 1 2\) 的概率使序列长度减少至少 \(\frac 1 4\),期望二分次数是 \(O(\log n)\) 的
但此时要注意横坐标相同的交点应该同时去掉,否则很可能一直随机到这个横坐标导致复杂度错误
具体随机的方式是根据逆序对数,先求出区间内总的交点数,然后随机一个排名 \(k\),取归并排序计算逆序对时第 \(k\) 对被计算的代表的交点
时间复杂度 \(O(n\log^2 n)\),但随机二分常数非常大,每次提交时间波动很大,感觉提交都不能稳定通过(
C. 背包计数
真是无敌了,才做过 QOJ8009 Growing Sequences 这个题,独立转化出来成数位 DP 用了比较简洁的方法,觉得不难就没记录 (埋下伏笔)
现在遇到了转化后的模型,然后场上根本就没看这个题???
从低位到高位按位考虑,不好处理的是如果一个较小的物品放了很多个会导致对高位产生影响,但此时我们把每种物品的摆放拆开,在当前位只考虑所有物品对当前位的影响,剩下的看作在高位摆放,就将对后面位的进位控制在 \(O(m)\) 范围
做数位 DP,设 \(f(i,j,0/1)\) 表示当前计算到第 \(i\) 位的贡献,向前一位的进位是 \(j\),是否超过当前上界的方案数,预处理出这一位摆放总和是 \(k\) 的方案数,\(i,j\) 均为 \(O(m)\),\(k\) 会达到 \(O(mk)\),朴素转移是 \(O(m^3k)\) 的
优化是直接枚举对下一位的进位是多少,这样可以算出加的范围,对预处理的系数做前缀和即可优化至 \(O(m^3+m^2k)\)

浙公网安备 33010602011771号