2025.6 训练笔记
Week 1
6.2 模拟赛
B. N门问题
分析性质可以得到选手选择的门下一轮会变成当前有奖概率最低的,原问题可以转化为 \(n\) 个球,开始所有球都在开头,每次选手从开头随机抽一个球把它放到末尾,主持人选一个非目标球扔掉
但是啥玩意啊,我想了半天 DP 不会做,结果告诉我 \(n>10\) 一定可以通过控制奇偶性使得选手拿不到奖品,\(n\le 10\) 爆搜就好了???
爆搜就设第一个是奖励,状态记录每个门选手选的概率,模拟双方的行动即可
C. 真正的运输
典题写不出来……
显然用线段树维护每个点按 dfs 序排成的序列,树剖
考虑耐久度,若 \(y\) 不在 \(x\) 子树中,那么 \(x\) 子树内每个节点 \(i\) 会被经过 \(siz_i\) 次,\(x\to y\) 路径上的点会被经过 \(siz_x\) 次,线段树上维护对应区间 \(siz\) 的和打标记
如果 \(y\) 在 \(x\) 子树中,不在 \(y\to x\) 路径中的点经过次数仍是 \(siz_i\),但是路径上的点会经过 \(siz_x-siz_i\) 次,树剖路径修改即可
查询直接查子树和或路径和
考虑活跃度,若 \(y\) 不在 \(x\) 子树中,\(x\) 子树内每个节点 \(i\) 会产生 \((dep_i+dep_y-2dep_{lca(x,y)})a\) 的贡献,拆括号后面 \((dep_y-2dep_{lca(x,y)})a\) 是常数,\(dep_i\times a\) 则同理线段树上维护区间 \(dep\) 的和
若 \(y\) 在 \(x\) 子树中,则 \(x\) 子树内点与 \(y\) 的 lca 不同,贡献也不同
提出 \(x\to y\) 的路径 \(x,u_1,u_2,\dots,u_k,y\),先按 lca 为 \(x\) 算,则 \(u_1\) 子树的点多了 \(2a\) 的贡献,对整个子树减,\(u_2\) 的子树还多了 \(2a\),再减……
如此进行下去,差分减的贡献,每个点要减的权值是它到根路径的权值和,则再用一棵线段树,直接对 \(x\to y\) 路径加 \(2a\),统计时这里每个点上的权值会对它子树内所有点产生贡献
查询子树则维护每个点上的贡献 \(v\times siz_i\) 之和,再单独计算 \(x\) 到根链上减去的总贡献乘上 \(siz_x\)
查询路径则维护每个点上的贡献 \(v\times dep_i\) 之和,\(x,y\) 到 lca 的路径分别算,再减去 lca 到根的总贡献乘上路径长度
复杂度 \(O(n\log^2 n)\),代码很长
6.3 模拟赛
B. 打怪兽
先考虑计算单点即攻击 \(m\) 次后排名为 \(x\) 的,二分答案 \(v\),计算剩余血量 \(\ge v\) 的怪兽个数,如果攻击 \(m\) 次,则血量 \(\ge v+m\) 的一定至少剩 \(v\),血量 \(<v\) 的不可能剩的更多,设初始血量 \(\ge v\) 的有 \(num\) 个,则 \(num<x\) 不可能,关键在于初始血量 \(v\sim v+m-1\) 的
血量 \(\ge v+m\) 的假设有 \(a\) 个,如果 \(a\ge x\) 那么已经满足了,否则会给总攻击次数贡献 \(ma\) 次,初始血量 \(v\sim v+m-1\) 的怪兽如果保持最后每个都 \(\ge v\),和前面的总贡献的攻击次数为 \(res\)
还有 \(num-x\) 个初始 \(\ge v\) 的可以变成 \(v-1\)(如果更小则会去减前面更大的而不是它),若 \(res+num-x\ge mk\) 则可行
修改是简单的,权值线段树维护序列,要求的是 \(\ge v\) 的数的数量与和,都容易维护
考虑求区间的和,先拆成后缀的和,即前 \(x\) 大血量的和,先求出单点的值 \(y\),考虑前 \(x\) 大被减少的次数,每个数至多减少 \(\min(a_i-y,m)\) 次,设总共至多减少 \(s\) 次
但是不一定所有减少的次数都给了前面,第 \(x+1\sim n\) 大的数必须 \(\le y\),所以它们至少被减了 \(\max(0,a_i-y)\) 次,设总共至少减 \(t\) 次
前 \(x\) 大被减少的次数 \(\le \min(s,mk-t)\),而它是前 \(x\) 大,贪心告诉我们如果一个减一在都满足条件时被选到后面的数了,那么它不如放到前面,因此减少的次数就是 \(\min(s,mk-t)\),时间复杂度 \(O(n\log^2n)\),不离散化写成 \(O(n\log n\log V)\) 可能被卡常
C. P11585 [KTSC 2022 R1] 直方图
6.6 模拟赛
A. 手办
啊 T1 好困难啊……
关键想法是考虑相对运动,每次把 \(\ge 1\) 的数拿一个 \(1\) 向右一格,可以看作是把 \(>1\) 的部分全拿起来向左一格
把 \(1\) 看成平地,\(0\) 是一个洞,\(>1\) 的部分是箱子,每次箱子全部向左移动,掉到洞里了就会把洞填上
用栈维护洞和箱子,如果栈顶是洞且和箱子距离不超过 \(k\),那么能把洞填上,把洞弹出栈,实现上可以把每个地方都先看成有洞,用共 \(a_i\) 个箱子填
在环上则用前面的箱子弹栈顶的洞即可,时间复杂度 \(O(n)\)
6.7 模拟赛
A. 失散的双子
唉脑子坏掉了,咋不会 T1 的……
每种点只有目前到它的路径条数为奇数的有用,朴素 DP 是设 \(f_{i,j,k}\) 表示前 \(i\) 组点,两种点目前到达的路径条数为奇数的点分别有 \(j,k\) 个时的答案,枚举当前组的点选哪种以及多少个点成为奇数的,复杂度 \(O(a^4)\)
key observation 是如果有不同种的点个数为奇数,那么一个点一定可以通过控制这个点是否连边来控制奇偶性,具体来说是一个点先和剩下点随意连边,根据此时的奇偶性来判断是否选这个点,方案数为 \(2^{t-1}\)
所以不需要记点数,只需要记 \(f_{i,0/1,0/1,0/1}\) 表示前 \(i\) 组中是否有第一种奇数、第二种奇数,总数是否为奇数,时间复杂度 \(O(n)\)
B. game
之前考过的原题,但我没补!!!
一眼减半警报器,把每个区间拆成线段树上 \(O(\log n)\) 个节点,能算出来在 \(O(\log^2 n)\) 次报警后去掉这个区间
减法是区间减,拆成线段树上 \(O(\log n)\) 个区间,但问题是区间子树内每个区间减少的总量不相同,不好快速找出总和小于等于 \(0\) 的区间
一种方法是记区间内最小值减到 \(0\) 还要减少的次数,这样子树内每个区间的减少量相同,就能打减法标记,每次修改完通过找小于等于 \(0\) 的区间来定位到触发警报的小区间,更新此警报
我的方法是把线段树每层单独拿出来建线段树,这样整段减少量就相同了,修改在每层的零散部分就是单点修改可以处理,由于总区间数仍是 \(O(n)\) 所以复杂度不变,但写起来会比较麻烦
每次找一个警报需要 \(O(\log n)\) 的代价,更新一次要做 \(O(\log n)\) 次区间修改,总复杂度 \(O(n\log^4 n)\),虽然卡不满但线段树上 set 常数巨大,然后换成 vector 复杂度不对但过了 /xk
Week 2
6.9 模拟赛
C. AT_xmascon20_d Determinant
全是原题的比赛,补之前没补的题
考虑快速计算矩阵的行列式,发现这个矩阵下半部分基本上都是 \(C\)
一种很厉害的推导方式是使用行列式的定义式,把对角线拆成 \(C+(1-C)\),枚举选对角线上或对角线以外列的行集合 \(S\),\(S\) 外的行选 \(1-C\),这样 \(S\) 外的数不会影响符号
于是答案能表示为 \(\sum_{S\subseteq[n]}(1-C)^{n-|S|}\det(B_S)\),\(B_S\) 为把 \(S\) 中行、列提出来形成的矩阵,对角线改成 \(C\)
分析 \(B_S\) 的性质,它最后一行 \(x\) 一定全是 \(C\),此时若 \(S\) 内存在 \(y\) 不是 \(x\) 的因数,则 \(S\) 内最大的 \(y\) 这一行也全是 \(C\),\(S\) 不满秩则 \(\det(B_S)=0\)
因此 \(S\) 所有数都是 \(x\) 的因数才有贡献,\(x\) 这一列只有一个 \(C\),可以去掉 \(x\) 行 \(x\) 列归纳下去,当 \(S\) 内所有数两两能整除时 \(\det(B_S)=C^{|S|}\)
提出 \((1-C)^{n-|S|}\) 后看成每个数权值是 \(\frac C{1-C}\),最后乘 \((1-C)^n\),考虑 DP,设 \(f_i\) 表示前 \(i\) 行选了最后一行的方案数,转移考虑上一个选的行 \(d\),它一定是 \(i\) 的因数,\(f_i=\frac C{1-C}(1+\sum_{d|i,d<i}f_d)\),要求 \(f_n\) 的前缀和
设 \(m=\frac C{1-C}\),形式可以用杜教筛优化,凑一个函数 \(g\),\((f*g)(i)=\sum_{d|i}f(d)g(i/d)\),发现有 \(\sum_{d|i}f(d)\) 的部分,考虑让除了 \(g(1)\) 的 \(g(i)=-m\) 就能凑出 \(m-f(i)\),再令 \(g(1)=1\) 则消掉 \(f(i)\),得到 \((f*g)(i)=m\)
时间复杂度 \(O(n^{\frac 2 3}\operatorname{polylog}(n))\),由于我预处理前面项带了 \(\log\) 所以也不会分析了
6.10 模拟赛
A. 玩游戏
被 T1 硬控了,直接贪心需要的性质很多,无脑考虑 Hall 定理,把 \(A,B\) 排序后一个 \(B_i\) 能匹配 \(A\) 的一个前缀 \(b_i\),限制最紧的也一定是 \(B\) 的一个前缀,最大匹配数是 \(n-\max_S(|S|-|N(S)|)\)
用线段树维护 \(|S|-|N(S)|=i-b_i=v_i\),要求 \(\forall i,v_i\le lim\),从前往后考虑每个 \(A_i\),每次贪心取符合条件的最大的 \(B_j\),取出后对剩下数 \(v_i\) 的变化是后缀加减,分类讨论当前是否匹配,线段树上二分找出符合条件的最大的 \(B_j\),时间复杂度 \(O(n\log n)\)
B. Permutation
要求转化为 \(i\) 所在的极长值连续段长度 \(\le a_i\),可以先把排列划分为若干段,然后把它们排列,要求相邻两段不能连接
考虑容斥,让这些段以任意方向随意排列,若 \(k\) 个缝隙连接则容斥系数为 \((-1)^k\),但是如果先划分后再容斥则会遇到长度为 \(1\) 的段没有顺序这种问题,无法计算
所以边划分边 DP,设 \(f_{i,j,0/1}\) 表示到第 \(i\) 个数,分了 \(j\) 个大段(容斥时连接后的),最后一个大段长度是/否大于 \(1\) 的方案数
枚举新的小段长度为 \(x\),它可以新建一个大段,也可以接在后一个大段后,但此时系数乘上 \(-1\),转移用减法,注意判断大段的长度是否 \(>1\),大段从 \(1\) 变长会有 \(2\) 的系数
时间复杂度 \(O(n^2)\),好像也有不用容斥,连续段 DP 的做法
C. AT_codefestival_2016_final_j Neue Spie
很牛的题啊
首先转化沿方向推下一格为找到当前方向第一个空余的格子放,这样要在每一行内分配一些格子给 \(U/D\),剩下的左边放 \(L\),右边放 \(R\) 即可
找哪些格子给 \(U/D\) 则贪心考虑,每行的 \(L/R\) 总个数是固定的,放 \(U/D\) 的个数也就固定了,把还需要 \(U/D\) 最多的那些列放上即可,最后判断如果有列有剩余或有列减到 \(<0\) 了则无解
然后需要找摆放顺序,发现一个 \(L\) 摆放时,它左边所有数都得填满,对其它方向同理,因此可以建出一张有向图,找到图的拓扑排序即可,但问题在于初始图中可能有环
发现把环上的每个格子中的方向放到环上它所指向的那个格子中,就能消去一个环,朴素的实现是 \(O(n^5)\) 的
还有一个问题是这个过程会不会终止,记每个格子到对应方向的边界的距离为势能,总势能为 \(O(n^3)\),每次消去环会使势能减少,且每遍历环上点一次会消耗 \(1\) 的势能,所以总复杂度为 \(O(n^3)\),需要精细实现
官解的代码也太巧妙了
6.13 模拟赛
A. 寻宝
赛时一直在对两维同时二分常数大的要死……
考虑二分一维,把分界线 \(mid,mid+1\) 走一遍就能知道 \(A,B\) 两部分之间走出走入的次数,走入走出外部 \(C\) 的次数用之前的二分得到的信息已经能求出
这样就变成了一个类似于三个点的图有欧拉路径,已知起点能找到终点,递归下去
朴素的写法要 \(14n\),在两层转移时有浪费,但我们每次走的时候回到边界的中心点,递归下一层时先来回 S 形走直到下一层边界的中心,然后直接走到边界另一端再返回中心,可以不浪费额外的步数,最终步数在 \(12n\) 左右
代码好难写啊
B. 改造城堡
神秘题,真不会啊
首先四联通网格图是二分图,将其黑白染色,要求是找出一棵生成树使所有叶子的深度奇偶性相同,即所有叶子在二分图同一侧
发现如果所有叶子都在点数较少的一侧,那么另一侧每个点至少两条边,总边数会大于等于总点数,与树的条件矛盾
因此叶子都在点数较多的一侧,两侧数量相同则无解
设两部分大小为 \(A,B\)(\(A<B\)),那么先找一组最大匹配,若不是完美匹配则无解,再从 \(B\) 中不在完美匹配中的点出发,找交错路(交替经过匹配边和非匹配边),注意不重复经过 \(A\) 中点,保证每个点至多在一条交错路中
如果 \(A\) 中存在点没有在增广时被经过则无解
证明:把点集分成 \(A_1,A_2,B_1,B_2\) 四部分,分别表示 \(A\) 中没经过的点,\(A\) 中剩余点,\(A_1\) 的匹配点,\(B\) 中剩余点,那么 \(B_2\) 中点均被经过,\(B_1\) 中点同 \(A_1\) 均未经过,\(|A_1|=|B_1|\),且每个 \(A_1\) 中点至少两条出边,而且没有向 \(B_2\) 中的边,所以 \(A_1,B_1\) 形成的导出子图有 \(2|A_1|\) 个点至少 \(2|A_1|\) 条边,与树的条件矛盾
这样 \(A\) 中点在交错路中已经满足度数至少是 \(2\) 了,接下来随便找边把所有链连成一棵树即可,复杂度为求最大匹配的复杂度 \(O((nm)^{1.5})\)
6.14 模拟赛
A. JOISC2017 手持ち花火 (Sparklers)
这个题好难啊
首先一定是两边的人向中间移动,这样发现一边中每个人的相对距离不变
每个人在碰到下一个人时可以先不点燃,等时间即将耗尽再点燃,相当于燃烧时间增加了 \(t\) 秒
二分答案,设最大速度为 \(v\),两个人相遇需要 \(\dfrac{x_{i+1}-x_i}{2v}\) 的时间,把时间统一乘上 \(2v\),相当于用 \(x_{i+1}-x_i\) 的代价,增加了 \(2vt\) 的贡献
至此问题被转化为了取一个数有 \(a_i\) 的代价,但会有 \(2vt\) 的贡献,任何时候总和不能为负,且必须从中间向两边取,问能否取完所有数
有经典的套路是贪心用 exchange argument 排序后选最优的然后把它和它依赖的节点合并,过程中维护总和和历史最小值即可,时间复杂度为 \(O(n\log n\log V)\)
但这题依赖关系是两条链,有更优的做法,转化后类似于双序列扩展问题,可以先从靠中间的地方开始分组,向后找直到总贡献为正了,然后就结束这一组,下一个数开启下一组
每一轮扩展中两边都尝试扩展,注意过程中时刻保持总和非负,两边谁先扩展无所谓,因为这一轮已经扩展出去的对后面的扩展不劣
扩展到不能扩展为止,再反过来从两边向中间分组,这时相当于倒过来考虑,把贡献和代价反过来,进行和上面一样的扩展
如果两次扩展加起来能覆盖所有的那就合法,因为如果有合法解则一定能被上述方法扩展出来,而上述扩展的一定是合法解
时间复杂度 \(O(n\log V)\)
B. 第一等悠然自得行程
朴素 DP 是设 \(f_{i,j}\) 表示以 \(i\) 开头到 \(n\) 长度为 \(j\) 的路径数量,转移为 \(f_{i,j}\gets \sum_{u< j}L_i^u\sum_{i\to k}f_{k,j-u-1}\)
考虑生成函数优化,把 \(f_{i,j}\) 看成函数 \(F_i(x)\) 的第 \(j\) 次项系数,在 \(i\) 处任意选自环的生成函数为 \(1+L_ix+L_i^2x^2+\dots=\dfrac 1 {1-L_ix}\)
则 \(F_i(x)=\dfrac{x}{1-L_ix}\sum_{i\to k}F_k(x)\)
由于每次乘的分式形式类似,最后 \(F_1(x)\) 形如 \(\dfrac{\sum_{i=0}^{n-1} a_ix^i}{\prod_{i=1}^n (1-L_ix)}\),但中间过程难以维护分子分母次数较高分式的加法,且最后查询也很麻烦
使用部分分式分解
部分分式分解是指把一个分子次数低于分母的分式分解为若干个分子次数低于分母的分式的和,其中若分母能因式分解为若干一次式的乘积,则分子均为常数
由于分母是若干一次式的乘积,所以分解后的分式分子均为常数,但注意 \(\dfrac 1{(ax+b)^c}\) 会分解出 \(c\) 个分式,其中分母取遍 \(ax+b\) 的 \(1\sim c\) 次方
考虑给每个分解出的因式乘上 \(\dfrac x {1-cx}\) 后得到什么,假设原来因式为 \(\dfrac{u}{(1-ax)^b}\)
若 \(a=c\),则 \(b\gets b+1\),但上面还有 \(x\),设 \(\dfrac u {(1-ax)^{b+1}}=\dfrac{u'}{(1-ax)^{b+1}}+\dfrac{v}{(1-ax)^b}\),解出 \(u'=\dfrac u a,v=-\dfrac u a\)
若 \(a\neq c\),则 \(\dfrac{ux}{(1-ax)^b(1-cx)}=\dfrac{u'}{(1-ax)^b}+\dfrac{v}{(1-ax)^{b-1}(1-cx)}\),解得 \(u'=\dfrac u{a-c}\),\(v=\dfrac u{c-a}\),此时还要继续分解 \(\dfrac{v}{(1-ax)^{b-1}(1-cx)}\),由于若分母存在 \((1-ax)^b\) 则必定存在 \((1-ax)^{b-1}\),这样能不断递归成子问题,求出乘上 \(\dfrac x {1-cx}\) 或 \(\dfrac 1{1-cx}\) 的分解,乘 \(\dfrac 1{1-cx}\) 的分解和上面类似
由于分母的总次数为 \(n\),所以维护的时间复杂度为 \(O(nm+n^2\log n)\),查询时可以 \(O(b\log V)\) 求出 \([x^d]\dfrac u{(1-ax)^b}=ua^d{d+b-1\choose b-1}\),总时间复杂度 \(O(nm+n^2\log n+qn\log V)\),使用光速幂可以做的更好
C. P7331 Dream and the Multiverse REMATCH
难以 \(\operatorname{polylog}\),考虑根号做法,如果直接莫队要计算一个点在一个区间内有多少可达点和一个区间内多少个点可达某个点,复杂度均为 \(n\sqrt qm\log n\)
瓶颈在计算信息上,使用莫队二次离线,把询问离线,扫描线
维护 \([1,i]\) 中可达 \(x\) 点的点数量,每个点可达的点是 \(O(m)\) 个 dfs 序区间,要 \(O(nm)\) 次区间加 \(O(n\sqrt q)\) 次单点查询
维护 \([1,i]\) 中 \(x\) 可达的点的数量,可达 \(i\) 的点是 \(O(m)\) 条到根路径的并,每个点会对这 \(O(m)\) 条路径上的点产生贡献,路径加单点查询转化为单点加子树查询,要 \(O(nm)\) 次单点加 \(O(n\sqrt q)\) 次区间查询,依然转化为 \(O(nm)\) 次区间加 \(O(n\sqrt q)\) 次单点查询
直接分块可以做到 \(O(nm\sqrt n)\),但是这可以更优,考虑多层分块,分 \(B\) 层修改复杂度为 \(Bn^{1/B}\),询问复杂度为 \(O(B)\),取 \(B=3\) 比较优
这个多层分块实际上长得跟 64 叉线段树很像,时间复杂度 \(O(nmn^{\frac 1 3}+n\sqrt q)\)

浙公网安备 33010602011771号