韬钤录 3
\(\boldsymbol{[2025/09/04]}\)
训练的两个方针大概是 薄弱板块做题单,以赛代练。剩下的就是做一些杂题。
- 个人觉得后者更重要。打比赛可以尝试录屏。
\(\boldsymbol{[2025/09/06]}\)
ARC184C
你就折纸折一下,然后把 \(01\) 序列打出来,oeis 一下。
或者根据对称性随便推推,都能得出如下结论:
\(w_{4n}=0,w_{4n+2}=1,w_{2n+1}=w_{n}\)
其中 \(w(x)=0/1\) 分别表示谷/山折,并且下标由原来的 \(\text{1—index}\) 改为 \(\text{0—index}\)。
相当于去掉一段后缀 \(1\),然后去掉末尾的 \(0\),再看末尾的结果。
对这东西设计 dp,记录 \(f_{i,0/1}\) 表示填了末尾 \(i\) 位,当前填的是 \(0/1\) 的最大值。
每次填一个 \(0/1\) 立刻计算贡献,填 \(0\) 则所有末尾为 \(0\) 的就没有后缀 \(1\) 了,计算 \(\bmod 4\) 结果即可。其他同理。
然后递归下去即可。复杂度 \(\mathcal{O}(n\log A)\)。
\(\boldsymbol{[2025/09/07]}\)
qoj 9518
写了 \(\mathcal{O}(q2^{n/4}+\frac{q^2}{w})\) 的做法。
也是把询问挂进 bitset 的套路。
对值域分四段,每段长 \(256\)。然后记 \(f_{i,j,k}\) 表示第 \(i\) 段中,第 \(k\) 个询问是否是 \(j\) 这个数的子集。
查询就四个 bitset 与起来,再异或一下。手写 bitset 跑飞快。
核桃编程 9 月月赛 I & florr IO Round 1
虽然出的狗屎,但是仍然有很多可以学习的地方(我光荣不光荣 rk.11 上分了)
没进 rk 前 \(10\),T2 会了没写完,T4 点分树的分没意识到然后没写,只能说水平就是菜。
第一题垃圾题,难点在于读懂题。第四题我目前不会正解,只会所有特殊性质。
然后 T2 卡线性做法,T3 的 \(\mathcal{O}(n\sqrt m\log n)\) 要求常数精细。
T2
一大坨啊,考虑把平方和的期望变成独立均匀随机两个位置,他们在同一极长段的期望。
变成求:
这个用脚维护做到 \(\mathcal{O}(n\log n)\)。
考虑顺序枚举 \(r\),动态更新 \(\sum\limits_{l=1}^r \max\left(0,\min_{i\in[l,r]} R_i-\max_{i\in [l,r]} L_i+1\right) a_l\)。
发现如果不和 \(0\) 取 \(\max\) 是好做的,类似 noip2022 T4 比赛,直接对于 \(\min,\max\) 用两个单调栈更新即可,只需维护一下 \(a\) 的前缀和 \(sa\)。
然后有这个限制考虑搞一个双端队列的东西(参考斜率优化),对于 \(L,R\) 的两个单调栈,在开头把不合法的位置给丢掉。
由于单调栈已经搞成了若干值相等的区间,每次比对开头两个区间是否被搞成空的了,如果空的就砍一刀,然后一直做。
这东西均摊依然是线性的。
T3
垃圾题。莫反,记 \(m=\max a_i\),求
然后注意到由于整除分块,\(\left\lfloor\dfrac{a_i}{d}\right\rfloor\) 总共只会变化 \(\mathcal{O}(n\sqrt m)\) 次。
然后后面的和显然能用线段树维护单点修改全局值,就维护前/后缀积之和一类东西。
于是做到 \(\mathcal{O}(n\sqrt m\log n)\),赛事用 zkw 线段树直接草过去了。
但是注意到如果一次修改很多,不如直接暴力 全局重构。
设置阈值 \(B=5000\),若当前连续修改超过 \(B\) 个,则直接对全局重构。
整除分块这东西显然卡不满,于是这样写跑挺快的,轻松在一半时限内通过。
复杂度会不会少 $\log $ 我不是很懂啊。
据说能通过对值域做扫描线做到少 \(\log\),但是懒得学了。
重构这种东西一忘再忘,极其不应该!
\(\boldsymbol{[2025/09/08]}\)
P14010
考虑四联通网格图,并且没有封口(补图八联通)这样一个图。
考虑这个图几乎是一棵树,具体的,如果把每行的连续段缩成一个点,然后紧贴着的连续段连边,那么这个图是一棵树。
然后注意到 \(x\to y\) 的最短路一定经过所有树上路径缩代表的段,段间移动是可以直接贪心考虑的。
于是直接点分治做完了,不同子树的限制直接容斥掉就行。后续需要一个排序所以是 \(\mathcal{O}(n\log ^2n)\) 的。
\(\boldsymbol{[2025/09/09]}\)
P13997
首先把这东西拆成向上的链和向下的链,然后向上的链贡献形如 \(a_i-d_i+k\),向下则是 \(a_i+d_i+k\),其中 \(k\) 为常数,\(d\) 是深度。
把二进制第 \(k\) 位为 \(1\) 看成 \(\bmod 2^{k+1}\) 的值落在 \([2^k,2^{k+1})\) 中,目的而为了拟合加法的性质。
然后成若干次查询某个位置到根的链在某个区间的值的个数的奇偶性。
关于值域扫描线,差分变成子树加,查询单点值的奇偶性,随便树状数组维护,复杂度两只 \(\log\)。
qoj 8839
神神结论题。首先第一个结论是每次 \(\bmod d\) 的 \(d\) 一定不超过 \(\max(a)/2\),于是取模可以变成减法。
第二个结论是每个数只会被减最多一次,然后根据这几个性质 dp 即可。
感觉自己根本想不到啊。
\(\boldsymbol{[2025/09/10]}\)
P12447
一模一样的题:P14012
这两题 \(\deg \le 3\) 显然是保证了树是二叉树。
首先想一个平方做法,就是把所有点按照距离 \(1\) 的位置排序,排成 \(p_1,p_2,\cdots,p_{n-1}\)。
然后发现每个 \(p_x\) 相当于往 \(S_x=\{1,p_1,\cdots,p_{x-1}\}\) 这个前缀连通块上挂一个点,于是只需要找到 \(S_x\) 中哪个是 \(x\) 的父亲即可。
而 \(x\) 的父亲一定是 \(S_x\) 中距离 \(x\) 最近的点,于是把点集里每个点都比较一遍找最小即可。
首先你发现排序容易做到 \(n\log n\) 次询问,然后发现点集里一个个问过去这件事非常蠢。
\(S_x\) 是树上子连通块这个性质要好好利用。由于二叉树,对 \(S_x\) 边分治,假设分治中心是 \((u,v)\),询问 \(\text{dis}(x,u)<\text{dis}(x,v)?\) 就能判断 \(x\) 应该连哪个子树。
每插一个点询问 \(\log\) 次,于是总询问次数大约是 \(2n\log n\),实际常数比较优秀。当然这题时间复杂度是 \(\mathcal{O}(n^2)\) 的,所以 \(n\) 不能开太大。
P10832
拉插维护信息板子题。
\(\boldsymbol{[2025/09/11]}\)
P11023
显然分上凸壳和下凸壳做。对于 \(y\ge 0\) 和 \(y\le 0\),先求出对应点集的凸壳,再在凸壳上写 dp。
然后发现这个 dp 满足四边形不等式,分治决策单调性优化一下即可。复杂度 \(\mathcal{O}(nk\log n)\)。
P12445
\(\boldsymbol{[2025/09/12]}\)
P5984
\(\boldsymbol{[2025/09/13]}\)
MXR6
T1 没想起来区间 dp 的交换位置与值域!
T2 缺少积累套路:如何找到 \(a_1\le a_2\le \cdots\le a_n\) 的前 \(k\) 小子集和?
初始把 \((\varnothing,0)\) 加入集合。pair 的含义是当前选了子集 \(S\),最后一个数出现在 \(x\) 位置。
然后每次优先队列删除 \((S,x)\),加入 \((S+\{a_{x+1}\},x+1)\) 和 \((S-\{a_x\}+\{a_{x+1}\},x+1)\) 即可。
qoj 8557
弱化版:https://www.luogu.com.cn/problem/P7830
但是弱化版要求做到更优复杂度,但是没有修改。
本文的 参考文章
\(\boldsymbol{[2025/09/14]}\)
螺旋
支如配。感觉这题套路也见挺多,但是自己就是不会。。。
先把最左最右的区间最大值拎出来贡献。那么剩下的区间都不跨过最大值。
对于左右两边,由于不跨过最大值,发现可以分别找一个数最左/右合法点来判断,于是只有 \(\mathcal{O}(n)\) 个支配点对。
离线扫描线,复杂度单 \(\log\)。
你的名字
首先注意到字符映射不会减少 LCP,于是排名可以上个 trie 树计几个量来搞。
然后 LCP 会变化当且仅当映射不是双射,就是有的字符会没掉啦!然后注意到这个只会发生 \(\vert \Sigma\vert =k\) 次,每次暴力重构即可。
复杂度 \(\mathcal{O}((q+l) k^2)\),足以通过。
树的直径
一棵树的全部直径具有相同的中点(可能在点上或边上)。由于边权可能为 \(0\),所以当直径长度为奇数的时候,直径的中点在一条边权为 \(1\) 的边中间;当直径长度为偶数的时候,可能为一条由边权为 \(0\) 的边组成的链。
为了处理第二种情况,我们使用点边容斥。巧合的是,对于边的容斥贡献,恰好与直径长度为奇数的情况对应的贡献抵消了。因此,只需要对于每个点求出赋边权的方案数使得其为某直径中点以及对应的直径数量之和即可。
使用树形 dp,记 \(f_{x,i},g_{x,i}\) 分别表示以 \(x\) 为根的子树内,若最远点到 \(x\) 的距离为 \(i\),对应的方案数以及距离为 \(i\) 的点数和。注意在根合并时需要特别考虑。
朴素实现是 \(\mathcal{O}(n^4)\) 的,但是注意到两个长度分别为 \(a,b\) 的 dp 数组的合并可以做到 \(\mathcal{O}(a+b)\),并且本质不同的 dp 状态只有 \(\mathcal{O}(n)\) 个。
因此,我们在合并一个点的子节点对应的 dp 状态时,将它们按照长度从小到大后排序再进行合并即可做到 \(\mathcal{O}(n^2)\) 的时间复杂度。
\(\boldsymbol{[2025/09/15]}\)
CF1789F
设循环次数为 \(k\)。首先显然只关心 \(k\) 为素数的情况。
若 \(k\le 3\),直接枚举 \(k-1\) 个分界点求 LCS,做到 \(\mathcal{O}(n^{2k-1})\),常数大概是 \(\dfrac{1}{120}\),足以通过。
若 \(k\ge 5\),发现 \(\left\vert T'\right\vert \le \left\lceil\dfrac{n}{k}\right\rceil\),直接 \(2^{\cdots}\) 枚举即可,复杂度就乘上两个 \(n\)。
P11039
很难想象自己几年前为啥不会做这个题。
虚树建出来,等价于两棵树虚树相等。
把第一棵虚树拎出来,设有 \(m\) 个点。枚举根是否为虚树根,则 \(ans=F(n,m)+(n-m)F(n,m+1)\)。
其中 \(F(n,m)\) 表示给定一颗大小为 \(m\) 的树,在点下/边上挂 \(n-m\) 个点的方案数。随便组合数 +Prufer 序列 算算即可。
复杂度是高贵的线性。
\(\boldsymbol{[2025/09/17]}\)
P6646
参考 My blog。
\(\boldsymbol{[2025/09/18]}\)
P6563
写出 \(f_{l,r}=\min_{k}(\max(f_{l,k-1},f_{k+1,r})+a_k)\),然后枚举 \(\max\) 取哪个,发现分界点有单调性。
直接双端队列维护即可。复杂度 \(\mathcal{O}(n^2)\)。
\(\boldsymbol{[2025/09/22]}\)
P14055
P9482
首先比较粗糙的比大小是后缀自动机那样,建出 \(T=S(\inf)\text{Rev}(S)(-\inf),m=2n+2\)。
然后比较 \(T[i,m]\) 和 \(T[m-i+1-2l,m]\)。
但是这样比较出错当且仅当回文串时,具体的:\([l,r]\) 出错当且仅当 \([l,r]\) 是回文串,并且 \([l,r]\) 扩展出最大的偶回文串 \([L,R]\) 后,\(S_{l-1}>S_{r+1}\)。
然后上几个二维数点即可,复杂度一只 $\log $。
CF2023F
枚举起点终点 \(s,t\),不妨 \(s\le t\)。然后把序列 reverse 一下再做一遍。
考虑 \(s\to l\to s\),\(t\to r\to t\) 这两个 耳朵 一定是顺着走的,贡献是 \(2(s-l)+2(r-t)\)。
接下来考虑 \(s\to t\) 这一段代价的上下界。
对于每条边分别考虑下界。如果这条边左边的沙子不能自给自足,那么这条边就至少要经过「右左右」三次;否则是至少经过一次。这个下界是能取到的,构造一下就好了。
其中 \(b\) 是 \(a\) 的前缀和。化简得 \(f_{l \sim r}(s, t) = 2(r - l) + \sum\limits_{i=s}^{t-1} ([b_i < b_{l-1}] - [b_i \geq b_{l-1}])\)。
这是最小子段和问题。把询问按 \(b_{l-1}\) 升序排序,每个点只会从 \(-1\) 变到 \(1\) 一次。
查询时就查询 \(l \sim r\) 的最大小段和。复杂度一只 \(\log\)。
P4901
按题意模拟,用树状数组倍增做到单 \(\log\)。
P3603
树分块板子。
\(\boldsymbol{[2025/09/23]}\)
P3992
首先转化成排序后对应差的绝对值,然后离散化对每条边算贡献。
转化成:给定权值 \(w_i\)。\(s\) 区间 \(\pm 1\),求 \(\sum \vert s_i\vert w_i\)。
这东西显然只能分块维护。由于离散化下来了可以逐块考虑。
整块修改的时候记一个 \(+T\) 的 tag,然后记录块内每个数出现的次数以维护 \(\sum\limits_{s_i\ge 0}w_i,\sum\limits_{s_i<0} w_i\)。
散块修改就暴力重构就行。
\(\boldsymbol{[2025/09/28]}\)
核桃模拟赛
The Extreme Slalom
- 幽默题,std 是枚举子集将军饮马。
根据距离的凸性,全局最优解 存在且唯一。
然后钦定初始状态,对所有 \(i\) 找它离前驱 \(pre\)、后继 \(suf\) 最短距离 \(\min (\text{dis}(i',pre)+\text{dis}(i',suf))\),\(i'\) 作为新点。
来回震荡,就过了。爆标了。
LittleElephantAndBoard
一列一列看,考虑 \((RG,BR,GB),(GR,RB,BG)\) 这样分类。然后只能 \(()\) 里的同一类连接,并且相同的不能相邻。
不妨只考虑第一类,答案 \(\times 2\),剩下的就把 \(RG,BR,GB\) 个数算出来,然后组合数小计算。
\(\boldsymbol{[2025/09/29]}\)
P7880
支配点对。当 \(\text{lca}=u\) 时,考虑包含 \(x\) 的支配点对,发现是 \(u\) 的非 \(x\) 子树中 \(x\) 的前驱后继。
用启发式合并 set 维护,然后二维数颜色即可。复杂度 \(\mathcal{O}(n\log ^2n +m\log n)\)。
P14099
区间取平均数当估价函数,每次挑最小的出来,中点分裂。
纯纯逆天狗屎。
\(\boldsymbol{[2025/10/01]}\)
P14062
首先转成 \(01\),然后打表观察发现每次操作只会交换一对 \(01\),\(\le x\) 分割的答案是 \(n-(g_x-f_x)\)。
其中 \(f_x\) 是 \(a_i>x,i\le x\) 的最大 \(i\),\(g_x\) 是 \(a_i\le x,i>x\) 的最小 \(i\)。
扫描线并查集维护即可,足以通过。
\(\boldsymbol{[2025/10/03]}\)
ABC279G
考虑记录前 \(k-1\) 个是否完全同色即可,转移就同色连续段整个一起考虑。复杂度线性。
\(\boldsymbol{[2025/10/04]}\)
P10004
二维二项式反演容易通过多项式那套做到 \(\mathcal{O}(n^2\log n)\),不过常数太大没啥用。
对于重复量提前计算即可做到 \(\mathcal{O}(n^3)\) 二项式反演。
考虑恰好 \(x,y\) 个转成钦定 \(x,y\) 个 \(<\),记作 \(f_{x,y}\)。即钦定 \(n-x,n-y\) 个极长上升子段,然后二项式反演。
接下来有一个显然的结论:一个原排列中的连续上升段,段内的值的位置一定是上升的。
也就是说,原排列中一段连续上升的元素,是按照其原顺序被划分至逆排列的若干个上升段的。
考虑原排列中第 \(x\) 个段在逆排列第 \(y\) 个段中长啥样,发现一定是一段连续的数。
既然顺序已定,我们可以设 \(c_{x,y}\) 表示原排列中第 \(x\) 个上升段中有 \(c_{x,y}\) 个元素划分在逆排列的第 \(y\) 个上升段中。
那么,我们钦定原排列、逆排列中各有 \(i, j\) 个连续的上升段,就相当于要有一个 \(i \times j\) 的矩阵,满足其中每一行每一列的总和为正,且整个矩阵总和为 \(n\)。
设 \(g_{i,j}\) 表示钦定原排列、逆排列中各有 \(i, j\) 个连续的上升段时的方案数,也就是合法的 \(i \times j\) 的矩阵 \(c\) 的数。注意 \(f_{i,j} = g_{n-i,n-j}\)。
设 \(t_{i,j}\) 表示和为 \(n\) 的 \(i\times j\) 矩阵的数量,易得 \(t_{i,j} = \dbinom{n+ij-1}{ij-1}\)。然后二项式反演得到 \(g\)。
\(\boldsymbol{[2025/10/07]}\)
qoj 8628
记 \(f(l,r)\) 表示区间 \([l,r]\) 替换出的最优答案。
- 对于单个 \(l,r\),相当于求前 \(m\) 小问题,线段树容易维护。
注意到 \(l\) 递增的时候,只需要考虑 \(r_l>r_{l-1}\) 的 \(r\) 即可。具有决策单调性。
分治,双指针加入删除即可。复杂度 \(\mathcal{O}(n\log^2 n)\)。
qoj 8629
首先有一个想法是在 Alice 函数中以 \(x\) 为起点,向四周 bfs 一遍得到每个点的深度 \(d\)。然后将每一条边由深度大的指向深度小的,这样就得到了一个最坏 \(n\) 次的做法。
考虑如果找到了一个深度大的点,直接向上跳其实很亏。
而我们期望随机 \(\sqrt n\) 次找到一个深度 \(\le \sqrt n\) 的点,此时再跳,期望就是 \(2\sqrt n\) 次询问了。
但是按上述方法,我们没法判断一个点深度是否 \(\le \sqrt n\),需要改变连边方向,给出更多信息。
发现由于是二分图,于是奇数深度的点只连向偶深度的,于是对于深度 \(>\sqrt n\) 的点,我们可以连成一个菊花状。发现是菊花状就可以排除了。
对于一条边 \((u, v):\)
-
如果 \(u, v\) 的深度都 \(\le \sqrt n\), 那么我们令其指向深度较小的点。
-
否则我们令其指向 深度为奇数 的点。
那么一个点的深度如果 \(>B\), 它的出度或者入度一定有一个为 \(0\)。如果随机到了这样的点,我们就接着随。
有一个细节是 菊花图 可能会导致所有点都是出度或入度有一个为 \(0\), 因此当随机次数 充分大 时应当直接 break。
CF2150C
两个排列不好做,经典套路是变成 \(a_i=i\)。设 Alice 选的是 \(S\),分析什么样的 \(S\) 合法:
发现对于 \(x < y, x \notin S, y \in S\),一定有 \(b^{-1}(x) < b^{-1}(y)\)。
考虑一个 \(dp\),设 \(dp(i, j)\) 表示考虑到 \(a[1\sim i]\),不在 \(S\) 中的最大的 \(b^{-1}\) 是 \(j\)。
然后 \(seg\) 优化转移,形如区间加区间 \(\max\) 的形式。
注意 \(seg\) 维护区间最大值初始的 \(-\infty\) 和区间查询时的 \(-\infty\) 要不同。
- 区间查询的 \(-\infty\) 应该更小(绝对值更大),以防初值加上负的 \(w_i\) 变小。

浙公网安备 33010602011771号