2025.3 训练笔记
前面由于省选完破防在 whk 所以从 Week 3 开始
Week 3
是云斗的线上集训,题还行,但 construction 的含量有点高了
QOJ4217 Graph Coloring
为什么见了那么多次二进制划分为不互相包含的集合还是看不出来……
给每个点 \(x\) 一个标号 \(a_x\),记录边 \(u\to v\) 的编号为最小的位使得 \(a_u\) 这一位上为 \(0\) 且 \(a_v\) 这一位上为 \(1\),容易发现对于 \(u\to v\to w\),由于 \(a_v\) 在前一条边中要求某位为 \(1\) 后一条边中要求某位为 \(0\),这两位不可能是同一个
但是如果 \(a_v\subseteq a_u\) 就找不到这样的位了,所以问题变成找到一种标号使得它们互不包含
\({14\choose 7}>3000\),于是给每个点的标号为 \(14\) 位二进制数中 \(\operatorname{popcount}=7\) 的数即可
CF1615F LEGOndary Grandmaster
第一步我觉得很困难啊,把所有奇数位取反,这样操作就变成了交换相邻两个不同的数,由于交换相同的数显然没有意义,可以当成能任意交换,这样两个串若 \(1\) 的个数相同则可以变得一样
然后考虑计算答案,设 \(S\) 中 \(1\) 的下标是 \(a_1,a_2,\dots,a_m\),\(T\) 中 \(1\) 的下标是 \(b_1,b_2,\dots,b_m\),则答案是 \(\sum_{i=1}^m |a_i-b_i|\)
这样还是不好计数,每次操作最多使某个前缀和变化 \(1\),把贡献拆到每个前缀上,\(S\) 的前缀和是 \(s_i\),\(T\) 的前缀和是 \(t_i\),最后要让 \(s=t\),答案下界为 \(\sum_{i=1}^n |s_i-t_i|\),通过从前往后逐位调整能取到下界
枚举 \(x=|s_i-t_i|\),计算这样方案的总数,注意到确定 \(x\) 后就能知道 \(i+1\sim n\) 中 \(S,T\) 内 \(1\) 的个数差,可以用组合数推式子计算(可以优化至 \(O(n)\)),也可以用 DP,设 \(f_{i,j}\) 表示前 \(i\) 个数 \(s_i-t_i=j\) 的方案数,\(g_{i,j}\) 表示 \(i\sim n\) 中 \(S\) 比 \(T\) 多的 \(1\) 的数量,答案是 \(ans=\sum_{i=1}^{n-1} \sum_{j=-i}^i f_{i,j}\times g_{i+1,-j}|j|\),时间复杂度 \(O(n^2)\)
CF1427E Xum
想利用同余方程组 \(ax+by=cx+1\) 得到相差 \(1\) 的两个数 \(cx,ax+by\),要求 \(cx\) 是偶数,\(a,b,c\) 均为非负整数
移项得 \((a-c)x+by=1\),令 \(a'=a-c\),关键在于找到两个互质的数 \(x,y\),解出方程后就把 \(b\) 调整成最小自然数,此时 \(a'<0\),然后令 \(a=a'\bmod 2\),\(c=a-a'\) 即可
构造与 \(x\) 互质的数,设 \(v=\lfloor\log_2x\rfloor\),令 \(y=x\oplus x\times 2^v\) 即可,由于 \(x\) 为奇数, \(y=(2^v+1)x- 2^v=2^v(x- 1)+x\),由于 \(2^v,x-1\) 均与 \(x\) 互质,则 \(y\) 与 \(x\) 互质
QOJ5357 芒果冰加了空气
之前模拟赛 T1 放这个题被硬控了,相当于求这棵树点分树的数量
合并两棵子树 \(u,v\) 时,假设子树内的删点已经确定了,要考虑刻画点被删的序列交错时造成的影响
如果 \(u,v\) 所在连通块没有因为 \(u\) 或 \(v\) 被删而断开,则两棵子树中删连通块中的点的顺序是重要的,会影响点分治的一个连通块,而当 \(u,v\) 其中一个被删后,两棵子树就独立了,剩下部分自然也独立
若 \(u\) 中影响 \(u\) 原来所在连通块的删点有 \(i\) 次且最后一次删的是 \(u\),同理 \(v\) 中有 \(j\) 次且最后一次删了 \(v\),那么假设合并后 \(u\) 这样的删点有 \(k\) 次(\(k-i\le j\)),要乘上组合数 \(k-1\choose i-1\)
用后缀和优化树形背包,复杂度 \(O(n^2)\),实际上记录的也是点分数上子树根的深度
QOJ5403 树数术
正解复杂度是 \(O(n\log n)\),然而我再见到它时想了一个 \(O(n\log^2n)\) 做法……
发现一个区间的答案只会受内部的限制和前面序列点的 lca 限制,考虑单侧递归线段树
设 \(calc(p,x)\) 表示计算线段树上节点 \(p\),当前面的数 lca 为 \(x\) 时节点内的贡献,节点 \(p\) 的贡献为 \(sum_p\),节点内点的 lca 为 \(lc_p\)
- 若左子树节点 lca 不是 \(x\) 的祖先,则左子树都没有贡献,直接递归右子树 \(calc(rs(p),lca(x,lc_p))\)
- 否则右子树的答案不受 \(x\) 影响,递归左子树计算新的贡献,\(calc(ls(p),x)+sum_p-sum_{ls_p}\)
查询时同理计算即可,复杂度 \(O(n\log^2 n)\)
CF1558F Strange Sort
直接做不好做,把数 \(a_i\) 看成宽为 \(1\) 高为 \(a_i\) 的长方形,目标是让每一行所有空格在前面,这样每一行的交换可以看作是独立的,答案就是每行交换次数的最大值,这样值域就减少到了 \(01\)
考虑对 \(01\) 序列排序的次数,则是每个 \(0\) 归位次数的最大值,一个 \(0\) 如果前面都是 \(1\) 则除了第一轮要讨论奇偶性,剩下的轮次都会一直前进,直到碰到了前面的 \(0\),前面的 \(0\) 归位后一步它才能归位
所以设第 \(i\) 个 \(0\) 归位要 \(s_i\) 次,它前面有 \(k_i\) 个 \(1\),在序列中下标是 \(p_i\),那么 \(s_i=\max\{s_{i-1}+1,k_i+(p_i\bmod 2)\}\)
所以答案是 \(s_m=\max_{i=1}^m k_i+(p_i\bmod 2)+m-i\),从下往上考虑行,每次只变化一个位置,将它转到下标上后线段树维护即可,复杂度 \(O(n\log n)\)
QOJ5047 Permutation
考虑序列最小值所在位置,它无法移动,把序列分成两半,这两半又各有一端的 \(c\) 个数可以移动
如果某次处理序列的最小值能移动,那么实际上它可以使能移动的范围增加 \(c\)
于是递归处理,\(solve(l, r, x, y)\) 表示当前在处理 \([l,r]\),左边能移动的范围是 \(xc\),右边能移动的范围是 \(yc\),其中序列中有些位置已经被处理过了
- 若 \((x+y)c>r-l+1\),则整个序列剩下 \(num\) 个元素可以随便移动,\(ans\gets ans \times num!\)
- 若剩下元素的最小值在 \(p\) 且它不能移动,则递归处理 \(solve(l,p-1,x,0/1),solve(p+1,r,0/1,y)\)(注意若序列长度不够则可能不产生可移动的段)
- 否则最小值肯定只能在一边移动,以左边为例,可以算出它的摆放方案,即能移动的范围中除去被确定的位置,而此时 \(x\) 不为 \(0\),意味着有 \(x\) 个数创造了这个范围且只有一个在区间外,它们已经确定了,因此 \(ans\gets ans\times (xc-x+1)\),递归处理 \(solve(l,r,x+1,y)\)
剩下未确定的元素个数和当前没被处理的最小值可以用线段树维护,时间复杂度 \(O(n\log n)\)
LOJ3077「2019 集训队互测 Day 4」绝目编诗
[AGC017F] Zigzag
逐条确定路线,我们只关心上一条路径,可以采用类似轮廓线 DP 的方式,设 \(f(x,i,s)\) 表示第 \(x\) 条路径,当前在第 \(i\) 行,\(s\) 中前 \(i-1\) 位是当前路径的轮廓,后面是上一条路径的轮廓
注意这里上一条路径的轮廓就是指对当前路径以后的限制,当前路径所在格可以直接通过 \(s\) 得到
转移时分类讨论当前路径向左还是向右,只需要注意如果当前路径向右而限制向左,则要调整限制,把之后第一个向右的限制去掉
时间复杂度 \(O(2^nnm)\)
P7056 [NWRRC 2015] Insider’s Information
神秘题,这是人想得到的东西吗……
要求是 \(b_i\) 在 \(a_i,c_i\) 之间,考虑类似拓扑排序的过程(为什么 * 1),连 \(a_i\to b_i,c_i\to b_i\) 的边,但它们去掉其中一个后就看作这两个入度都没了,\(b_i\) 就可以选
按拓扑序从两边往中间摆放(为什么 * 2),选择每个数是放在左边一半还是右边一半,发现一组中第一个摆放的数不可能是 \(b_i\),而若第二个数是 \(a_i/c_i\),摆在和第一个数不同的一边,第三个数随便放都满足,同理若第二个数是 \(b_i\),则放在和第一个数相同的一边第三个数就能随便放
因此对每个数统计它成为第二个数的数对中要它在左边的多还是在右边的多,放在较多的一侧,就能保证至少一半的限制满足
Violet Line - 2025年国赛第一阶段训练_模拟赛#1
题意是给一张 DAG,保证 \(1\) 能到图中所有点,多组询问,每次给出询问点集 \(S\),求选不同的 \(k\) 个点满足 \(S\) 中每个点都有从 \(1\) 出发到它的必经点在选出的 \(k\) 个点中且选出点中只有那个点能到它的方案数,\(n,q\le 10^5,m\le n+50,1\le k\le 4,\sum |S|\le 10^5\),2.5 s
考虑外向树的情况,每个点的必经点就是它的祖先节点,那么对询问点集建虚树,树上 DP 一下选 \(k\) 个点的方案即可
如果是 DAG 则考虑求必经点,建出 DAG 的支配树,但是与树不同的情况是如果 \(x\) 不是 \(y\) 在支配树上的祖先,并不能说明 \(x\) 到不了 \(y\)
还是把询问点集支配树上的虚树建出来,对虚树上的每条边求哪些点是可以选的,能选的点要求它们不能到达子树外且在询问点集中的点
显然 \(x\) 能到的点它支配树上的父节点也能到,因此虚树上每条边满足要求的点是一个后缀,从深度较深的点开始向上倍增
刻画选出点的形态,如果选了 \(x\) 子树,则它到根的链上没有点可以被选了,这意味着链上所有点在链外的子树中如果有询问点集中点则子树中至少选一个点,那么这些链外的子树个数 \(<k\),且 \(x\) 不能到达所有子树的根,这是 \(x\) 合法的充要条件
因此倍增时可以暴力枚举所有子树的根,由于 \(m\le n+50\) 因此可以找出一棵生成树后暴力求出有非树边的点的可达性,查询可达性则枚举子树内所有这样的点,时间复杂度 \(O(n\log nkt),t=m-n\)
Week 4
哦回 MX 了,喜提办公室座位,不过怎么又不能坐了(
P5853 [USACO19DEC] Tree Depth P
把 \(u\) 深度的贡献拆到 \(u\) 的每个祖先 \(v\) 身上,若 \(v\) 为 \(u\) 祖先则 \(a_v<a_u\) 且 \(u,v\) 之间没有比 \(v\) 小的数
考虑求逆序对数为 \(k\) 的排列数的 DP,设 \(f_{i,j}\) 表示长度为 \(i\) 的排列逆序对数为 \(j\) 的数量,转移则是在排列末尾加上一个数,枚举它和前面数的大小关系,即它在 \(i+1\) 个数中的排名,用前缀和优化可以做到 \(O(n^3)\)
每次加入时加入的下标在当前序列首尾就行,所以加入各个数的顺序可以调整为 \(u\to v,u-1\to 1,v+1\to n\), 发现只有加入 \(v\) 的时候有限制,\(a_v\) 必须是已经加入的数中最小的,且若 \(u<v\) 会新产生 \(v-u\) 个逆序对
枚举 \(x=|u-v|\),则每次撤销一次转移,类似于撤销背包的过程,然后枚举下标统计贡献即可,复杂度 \(O(n^3)\)
P6277 [USACO20OPEN] Circus P
好难啊,咕咕咕
QOJ5523 Graph Problem With Small n
状压判断每两个点间是否有哈密顿路径,朴素枚举起点,记录已经经过的点和末尾点的 DP 是 \(O(2^nn^3)\) 的
优化则是不要在状态中记录当前点,而是设 \(f(i,S)\) 表示从 \(i\) 出发经过 \(S\) 中点后可能成为末尾点的点的集合,设 \(N(x)\) 表示与 \(x\) 相邻的点组成的集合,转移则考虑加入一个点 \(x\),如果 \(N(x)\cap f(i,S) \neq \varnothing\),则 \(x\) 可以作为 \(f(i,S\cup \{x\})\) 的末尾点,复杂度 \(O(2^nn^2)\)
更进一步,发现每条路径都会经过点 \(n\),它把路径分成两半,那么只用以 \(n\) 作为出发点 DP,枚举其中一边的路径点的集合 \(S\),枚举 \(f(n,S)\) 中的所有点作为 \(u\),则 \(f(n,U/S\cup \{n\})\) 中的点都能作为 \(v\),让 \(ans_u\gets ans_u\cup f(n,U/S\cup \{n\})\) 即可,复杂度 \(O(2^n n)\)
QOJ5418 Color the Tree
显然不同深度的点互不影响,单独考虑每层的点
把同一深度的点按 dfs 序从小到大排序,设 \(f_i\) 为前 \(i\) 个点的最小代价,第 \(i\) 个点是 \(x\),它前面的点和它的 lca 深度单调不增,于是可以用单调栈维护,求出 \(x\) 和第 \(i-1\) 个点的 lca,把栈顶深度更大的全部弹出,用线段树维护转移,每次修改栈中元素时在线段树上区间加减,查询最小值即可,复杂度 \(O(n\log n)\)
QOJ5519 Count Hamiltonian Cycles
我觉得这题不简单啊
考虑答案下界,将绝对值拆开,分摊到每个「缝隙」产生的贡献,前 \(i\) 个点和后 \(n-i\) 个点之间有 \(x\) 条边,设 \(w_i,b_i\) 分别为 \(W,B\) 个数的前缀和
哈密顿回路中每个点度数为 \(2\),所以前 \(i\) 个点内部有 \(\frac {2i-x}2\) 条边,而前 \(i\) 个点内最多有 \(2\min(w_i,b_i)\) 条边,因此
又因为 \(x\) 为偶数,\(x\ge 1\),所以 \(x\ge \max(2,2|w_i-b_i|)\),下界可以取到,刻画此时路径的形态
- 若 \(w_i>b_i\),则前 \(i\) 个点中有 \(w_i-b_i\) 条形如 \(WBWB\dots BW\) 的路径
- 若 \(w_i<b_i\),则前 \(i\) 个点中有 \(b_i-w_i\) 条形如 \(BWBW\dots WB\) 的路径
- 否则 \(w_i=b_i\),前 \(i\) 个点有一条形如 \(WBWB\dots WB\) 的路径
设 \(f_i\) 表示前 \(i\) 个点组成的不同路径组的数量,每次新增一个点,讨论 \(W,B\) 的数量关系,合并两条路径或延长一条路径,为了避免当路径只有一个点时造成的方向问题,每条相同路径算两次(此时正反路径算两条不同路径)
- 如果 \(w_i>b_i\),则若加入 \(W\) 则它单独成为一条路径,\(f_{i+1}\gets f_{i}\),否则若 \(w_i>b_i+1\),则合并两条路径,\(f_{i+1}\gets f_i\times (w_i-b_i)\times (w_i-b_i-1)\),若 \(w_i=b_i+1\),则在路径首或尾加入 \(B\),\(f_{i+1}\gets 2f_i\)
- 如果 \(w_i=b_i\),则在路径与下一个字母不同的一端加入它,\(f_{i+1}\gets f_i\)
- 如果 \(w_i<b_i\),同第一种转移
最后答案要除以 \(4\),因为先去掉重复计算的次数,然后正反路径对应的环相同,时间复杂度 \(O(n)\)
QOJ5423 Perfect Matching
拆绝对值,\(a_i-a_j=i-j\) 或 \(a_i-a_j=j-i\),得 \(a_i+i=a_j+j\) 或 \(a_i-i=a_j-j\)
把点看成二维平面上坐标是 \((a_i-i,a_i+i)\) 的点,每行、每列的点之间有连边
对每行、每列也新建一个点,把原来的点看成连接行、列的边,那么要求把所有边划分为若干长度为 \(2\) 的链
对每个连通块处理,如果边数为奇数则无解,否则随便找一棵生成树,将每个点除了连向父节点的还未匹配的边两两匹配,如果有剩余边则把连向父节点的边加入匹配,这样到根节点处一定剩偶数条边,因为每次去掉的也是偶数条边,可以完成构造,复杂度 \(O(n\log n)\)
CF1801G A task for substrings
对所有 \(s\) 串建立 AC 自动机,将 \(t\) 在自动机上跑,那么可以用右端点在 \([1,r]\) 减去右端点在 \([1,l-1]\) 的串数求出右端点在 \([l,r]\) 之间的串数
问题是还要减去左端点在 \([1,l-1]\) 且右端点在 \([l,r]\) 的串数
找到这样的右端点最靠右的串,假设它的右端点为 \(x\),它是 \(g_x\),则合法的串要么是它 \([l,x]\) 间的子串,要么右端点 \(>x\),对于前一个可以在 AC 自动机上预处理出来,每个自动机上点贡献为它 fail 树上的祖先节点中末尾点的数量,把字符串每位在自动机上的对应点找到后做后缀和,后一个则仿照上面的做法即可预处理
最后一个部分是怎样找到这样的 \(x\) 和 \(g_x\),可以在 fail 树上预处理出每个点祖先节点中对应串长度最长的,将 \(t\) 放在自动机上跑,能求出每个 \(x\) 对应的 \(g_x\),然后是要求找到最靠右的 \(x\) 使得 \(x-len_{g_x}+1 < l\),可以在线段树上二分
时间复杂度 \(O(\sum |s|+m\log |t|+|t|)\)
2025.3.26 模拟赛 B
做法挺多的, 题解做法是找支配对,如果不考虑颜色,把数从小到大排序后只有相邻的数有用,加上颜色就是颜色段交接的地方有用,可以直接维护做到 \(O(n\log V)\)
我则是直接在 Trie 上维护,对每个节点记录它子树内的异或最小值 \(mn\),以及子树内是否为同一颜色,如果是则是哪种颜色
每次修改时 pushup,分类讨论,设 \(x\) 的子节点分别为 \(ls,rs\)
- 如果 \(ls,rs\) 至少一个子树不是同一颜色,则直接用它们的 \(mn\) 更新 \(mn_x\)
- 否则它们内部不产生贡献,若它们颜色不同,由于数值不会更改可以预处理出它们之间异或得到的最小值,否则说明 \(x\) 子树内是同种颜色
预处理时由于单链上的点不需要处理,用压缩 Trie 可以做到 \(O(n\log V)\),直接做要遍历每个点的子树,但单链上的点不用被考虑,复杂度不会分析,可能退化为 \(O(n\log^2 V)\)
2025.3.31 模拟赛 C
官方题解挺清楚的,复制过来补充一下
记一个点的权值为其每一维的坐标之和,记 \(M = \left \lfloor \frac{\sum_{i = 1}^{n}(p_i + 1)}{2} \right \rfloor\),答案即为权值为 \(M\) 的点数,下面证明这个结论。
将 \(x\) 到达 \(y\) 看作偏序关系,答案即为该偏序集上的最小链覆盖,通过 Dilworth 定理将其转化为最长反链,即最多能选择多少点使得其两两之间互相不可达。显然权值相同的点互相不可达,因此答案的下界为权值为 \(M\) 的点数。
下证答案上界为权值为 \(M\) 的点数,只需构造一组方案使得链数为 \(M\)。若一条链满足起始位置与终止位置之和为 \(\sum_{i = 1}^{n} (p_i + 1)\),则将其称为对称链。由于链上的点权值连续,所以一条对称链上必然有且仅有一个权值为 \(M\) 的点。
实际上对称链和权值为 \(M\) 的点形成双射
下证可以构造一组方案,使得两两不交的对称链覆盖所有点。
记 \((x_1, x_2, \ldots, x_{n - 1}) + x_n = (x_1, x_2, \ldots, x_{n - 1}, x_n)\)。
考虑归纳证明。\(n = 1\) 时,结论显然成立。
当 \(n > 1\) 时,若 \(n - 1\) 满足,则取出 \(n - 1\) 维的对称链 \(u_1 \to u_2 \to \cdots \to u_k\),构造如下几条链:
不难发现,这样的链是 \(n\) 维的对称链,且两两不交地覆盖了所有点,故链数可以为 \(M\)。\(\square\)
上述证明实际上是 Sperner 定理的推广。
Sperner 定理:记 \([n]=\{1,2,\dots,n\}\),\(P(S)\) 为集合 \(S\) 的所有子集关于包含关系构成的偏序集,\(F(S)\) 为 \(P(S)\) 的最长反链,则 \(|F([n])|\le \binom{n}{\lfloor\frac n 2\rfloor}\)
证明可以考虑类似上面构造对称链,形如 \(s,s+1,\dots, n-s-1,n-s\),还可以用不等式
于是问题转化为求有多少点的权值为 \(M\)。相当于将 \(M\) 个球放入 \(n\) 个盒子,第 \(i\) 个盒子内的球数量在 \([1, p_i]\) 之间。
这是经典的容斥。记 \(f(S)\) 表示恰有 \(S\) 集合内的盒子球数超过上限,\(g(S)\) 表示至少有 \(S\) 集合内的盒子球数超过上限,\(s(S) = \sum_{i \in S} p_i\),所求即为 \(f(\varnothing)\)。
数据范围 \(n \le 32\),考虑 meet in the middle。
其中 \((*)\) 式的转化用到了范德蒙德卷积。
范德蒙德卷积在上指标是负数时也是正确的,可以考虑生成函数的证明,\((1-x)^n (1-x)^m=(1-x)^{n+m}\),将式子用二项式定理展开,发现当 \(n,m\) 为负数时仍然成立
将 \(S_0\) 与 \(S_1\) 分别按照 \(s(S)\) 排序,双指针加前缀和即可,复杂度 \(\mathcal O(n^2 2^{\frac{n}{2}})\)。
QOJ4923 整数
组题人给了另一种做法,考虑对每个位置 \(i\) 找它的值的前驱,即 \(p_i-1\) 所在的位置
注意到操作的位如果原来是 \(0\),则操作后 \(1\) 的个数一定增加 \(1\),否则 \(1\) 的个数不增
先将每个数都操作一次,这样 \(0\sim n-1\) 位上是 \(1\),再依次操作每个数,如果操作到 \(0\) 则会让 \(1\) 个数减少,之后无论操作哪个数 \(1\) 个数都只会增加,于是这样可以找出哪个位置上的数是 \(0\)
然后再对 \(0\) 操作两次,这样 \(0\sim n\) 位上都是 \(0\),这相当于清空操作
之后随机一个操作位置的顺序,从前往后依次将每个位置执行两次操作,设操作位置 \(i\) 后两次操作后 \(1\) 的个数分别是 \(s,t\),如果 \(s<t\) 则说明 \(p_i\) 位原来是 \(1\),先变成 \(0\) 后变成 \(1\),而 \(p_i\) 位是 \(1\) 说明 \(p_i-1\) 被操作了两次,即 \(p_i-1\) 对应位置在现在的操作顺序中在 \(i\) 之前,\(p_i\) 的前驱一定是这次操作序列中 \(i\) 前面的数,如果 \(s\ge t\) 则同理说明 \(p_i\) 的前驱一定是这次操作序列中 \(i\) 后面的数,注意每轮询问后要清空
重复 \(T\) 次后期望每个位置的前驱已经被找到,分析这样做的正确率,每个不正确的前驱每轮期望有 \(\frac 1 2\) 的概率被排除,\(T\) 轮后所有数的不正确前驱均被排除的概率是 \((1-(\frac 1 2)^T)^{n(n-1)}\),\(T\) 取到 \(O(\log n)\) 即可,询问次数大概为 \(O(n\log n)\),实际上取 \(T=30\) 正确率就很高了

浙公网安备 33010602011771号