2024.12 杂题记录(上)
我为什么需要考省选。明明都没有希望进队了。
NOI2023 D1T3
注意到判定就是 dfs 树看作 \(T\) 时,对于额外边不允许存在横叉边,也就是必须都是返祖边(无向图 dfs 树不考虑前向边),即以某个 \(s\) 为根时要求任意非树边的两个端点均形成祖先关系。那么只需要计算多少条边符合条件即可。
记符合条件的边数量是 \(c\) 的话就会产生 \(2^c\) 的贡献。但是我们要求重复的只计数一次,可以考虑容斥原理。对于关键点集合 \(S\) 计数有多少边满足以 \(S\) 中任意点为根时这条边的端点均形成祖先关系即可。带上 \((-1)^{|S|+1}\) 的容斥系数直接统计答案。时间复杂度 \(\mathcal O(2^kk(n+m))\),期望得分 \(36\)。
考虑特殊性质 \(\text{B}\):在以 \(1\) 为根的情况下不存在横叉边。不妨设树根是 \(1\)。考虑对容斥的做法使用数据结构优化。对于关键点集合 \(S\) 考虑如何刻画符合条件的非树边。可以对点集 \(S\) 建立虚树。显然一条边合法可以是:完全被某条虚树上的边给包含;另一种情况是,落在虚边上对应路径的某个点 \(u\) 向外一条边 \((u,v)\) 使得 \(v\) 不在虚树上,那么要求起点(非树边深度较大的端点)必须在 \(v\) 子树之中的同时,不构成该点为子树意义下的横叉边。注意,如果出现虚树上度数为 \(2\) 的根且根不在 \(S\) 之中就需要将合并一下两个儿子的路径,否则会违反判定 \(1\)。注意到性质 \(\text{B}\) 告诉我们没有横叉边,在这个条件下我们可以暂时认为对于两个儿子的子树都在,我们就可以认为它也在虚树上。
那么可以对于所有 \(S\) 构成的虚树 \(T'\),将 \(T'\) 在以 \(1\) 为根的意义下的根位置 \(R\) 进行答案的统计。注意到由于没有横叉边,因此子树内外两部分是独立的。那么就需要换根维护 \(out_R\) 表示以 \(R\) 为根时,在以 \(1\) 为根意义下 \(R\) 的子树补范围中非树边的个数。这个是经典的换根 dp,容易 \(\mathcal O(n)\) 求出。结合性质可以进行 dp。\(f_u\) 表示仅考虑 \(u\) 子树此时 \(u\) 为虚树根的选取贡献和。即在 \(u\) 子树中选取 \(S\) 得到的容斥系数乘 \(2\) 的合法路径个数次方之和。考虑转移分为两种:\(\ge 2\) 个儿子选了;恰好 \(1\) 个儿子选了且自己也选入 \(S\)。此时细节就是要从子树中位置 \(v\) 来接。此时虚边对应路径添加了 \((u,v)\)。此时需要维护返祖链终结在这个路径以及这个路径本身的贡献。
对于路径 \((u,v)\) 包含非树边的情况,可以使用 dfs 序来刻画。形如一个直链上一个区间内的 \(v\) 以及 \(\mathcal O(1)\) 个区间内的 \(u\)。当然你要做的是在 dfs 过程中实时维护这个 \(\times 2\) 的系数,也就是访问 \(f_u\) 时你在数据结构中要有的是 \(f_v\times 2^{\text{coef}(u,v)}\)。
考虑将非树边视为更新操作,那么对于在端点深度较浅的位置新增一条非树边一个朴素的操作就是进行子树 \(\times 2\)。那么对于另一种贡献,返祖链合并到虚树上时,那么其实是对旁边一个子树都有更新的,那么加入一个点 \(u\) 就需要求出子树内有多少个合法的非树边,记为 \(in_u\),可以直接进行树上 dp。那么对于数据结构的操作,就是枚举所有 \((u,v)\),对于所有除了 \(v\) 以外的子树,对于数据结构执行乘 \(2^{in_v}\) 的操作。
对于统计答案,还需要执行子树求和的操作。操作都是对于子树的,可以直接将它拍成 dfs 序,这样子树操作可以转化为区间乘区间加。直接使用线段树维护即可做到 \(\mathcal O(n\log n)\) 的时间复杂度。结合算法 \(1,2\) 期望得分 \(72\)。
拓展到正解。
瓶颈在于:对于虚树虚点自己不选,但存在两个儿子被选导致其出现在虚树上的方案统计。问题在于这个会导致合并路径。那么对于一个横叉边而言,其不形成祖先关系。从 dfs 序的角度进一步思考,两个端点对应的子树区间也是不交的。那么意味着当虚树根连接的两个点 \(v_1\in[l_1,r_1],v_2\in[l_2,r_2]\) 时是可以进行插入的。也就是说贡献在于被 \(v_1,v_2\) 包含的点。注意这个附加代价当且仅当只有两个儿子才可以进行。因此这是一个二维问题。我们发现一个更优美的性质,这个造成贡献当且仅当虚树根取到 \(\text{lca}\) 上。直接挂在这个 \(\text{lca}\) 上。当前统计 \(f_u\) 时直接在 \(u\) 上扫描线所有 \(u\) 的所有儿子互相算一下贡献即可。容易抽象化成若干在二维平面上的矩形操作。因此这个内部可以用一棵线段树来维护。
总复杂度 \(\mathcal O(n\log n)\)。
QOJ5020
令 \(t=\text{lca}(x,y)\),将询问转化为 \(x\to t\) 以及 \(y\to t\) 的两条链。直接相加的话答案会多计算 \(t\) 子树距离 \(t\) 边数 \(\leq d\) 的点。同时还需要计算 \(t\) 子树外距离 \(t\) 边数 \(\leq d\) 的点数。其实可以直接容斥一下,全局的系数为 \(1\),添加一个子树内的询问系数为 \(-1\)。瓶颈在于维护直链 \(x,y\) 的 \(f(d,x,y)\)。此时就是链上的点数加上 \(x\to y\) 每个点挂着的其他子树深度 \(\leq d\) 的点数和。容易想到进行轻重链剖分。这个对于每个点是独立的,因此只需要维护 \(f(d,1,x)\) 表示对于 \(1\to x\) 链有多少点距离在 \(\in[1,d]\)。这个可以直接差分贡献。
注意到对于一条路径而言,最多只有 \(\mathcal O(\log n)\) 条轻边。对于轻边就会导致其需要考虑重子树信息。但是对于大部分的,我们需要处理 \(g_{u,d}\) 表示 \(u\) 所有轻子树距离 \(u\) 边数 \(\in[1,d]\) 的点数。从上往下 dfs 的时候维护一下前缀和即可。对于这些轻边而言,我们需要处理的是 \(f_{u,d}\) 表示 \(u\) 子树内距离 \(\leq d\) 的点数。计算 \(f(d,1,x)\) 需要动态维护 \(g\) 的和以及 \(\mathcal O(\log n)\) 个单点 \(f\)。拆下贡献。考虑维护 \(g\),因为轻子树的大小总和为 \(\mathcal O(n\log n)\),因此可以直接暴力插入单点,维护树状数组,在 dfs 过程中维护即可。考虑求单点 \(f\),可以全部离线下来做然后 dfs 的时候树状数组维护即可。
因此总时间复杂度 \(\mathcal O(n\log^2n)\)。
QOJ7859
考虑对于一个固定的 \(S\) 怎么做。显然操作 \(1\) 就是全体减去 \(\min\),那么当且仅当在 \(\min>k\) 时我们会执行第一种操作。考虑直接进行 dp,\(f_i\) 表示已经执行了 \(i\) 点伤害接下来最少需要多少次。有转移 \(f_i=f_{\max(i+k,\min(S_p[S_p>i]))}+1\)。 容易发现这个形成了树的结构,需要动态查询 \(0\) 的深度。可以使用 lct 或者分块加速。容易发现倒序扫然后删除 \(S\) 是可以接受的,因为这样可以用并查集来维护后继。时间复杂度 \(\mathcal O(n\sqrt n\alpha(n))\)。
QOJ7905
trick:不分裂仅合并的状物都可以用并查集替换掉 \(\log\) 的复杂度。
有一个显然的 \(\mathcal O(n^3)\) 的 dp 做法。我宣布这满足四边形不等式,然后 \(\mathcal O(n^2\log n)\) 过不去。观察一下转移,需要快速维护的是 \(w(l,r)\) 表示被 \([l,r]\) 完全包含的线段价值和。扫描线一下所有线段,那么对于 \(w\) 就会形如前缀加。数据结构里同时维护,就是对 \(g\) 的前缀加。查询的是前缀 \(\max\)。使用并查集维护,对于一次前缀加,若前缀 \(\max\) 大于下一个比它大的数,那么就合并两端。不会出现分裂的情况,只会出现合并。因此时间复杂度 \(\mathcal O(n^2\alpha(n))\)。注意要以划分段数为阶段进行 dp。
P4785
字典序考虑直接从前往后扫。首先注意到只有 \(4\) 种情况。以上三角 \(1,2,3\) 为例。如果 \(1/2\) 之一是三者的最小值,那么决策唯一。否则需要决策 \(1/2\) 在哪一侧。直接设计一个 dp 表示 \(f_{u,i}\) 表示对于 \(u\) 子树如果当前值为 \(i\),在最优交换条件下 \(i\) 最终的位置。只需要关心少量的值。使用记忆化搜索即可做到 \(\mathcal O(n\log^2n)\)。
T549518
每次操作大概就是剪掉一个连通块。难点在于想到用决策树来刻画一个策略,让它变成确定性的。考虑对于这个确定形态的决策树,令其除了叶子节点都有两个子节点。那么其询问的轮数就是在决策树上的深度,每次往决策树左右的一个子树中走。定义一个点(原树上的边)的标号 \(rk_{u,v}\) 是 \(dep\) 表示其第几次被选取。那么问题在于确定这个决策树。先考虑对于一个决策树 \(G=(V,E)\) 的答案,停在 \(u\) 就要求其邻边均被选入 \(E\),其期望得分 / 权值即为 \(w_up_{m+1-\max(rk_{u,v})}\)。事实上一个决策树形态可以由每个边的 \(rk\) 唯一确定,我们要求 \(\forall rk_{e_1}=rk_{e_2}\in[2,m],\exist e_3\in\text{path}(e_1,e_2),rk_{e_3}<rk_{e_1}\)。
注意到这个决策树很像点分树。为了方便进行树上 dp,考虑将原树定根为 \(1\),并且让树是外向的。类似于点分治的思想,考虑用到叶子路径的 \(k\) 的前缀 \(\max\) 集合 \(S(x)\) 来刻画路径。\(x\) 可以是边或点。那么一个标号方案要求 \(u\) 的两条出边 \(e_1,e_2\) 有 \(S(e_1)\cap S(e_2)\subseteq\lbrace m+1\rbrace\),并且 \(k_{(u,v)}\notin S(v)\)。直接树上做状压 dp,\(f_{u,s}\) 表示 \(S((u,fa_u))=s\) 的最大期望即可。时间复杂度 \(\mathcal O(n3^k+nk2^k)\)。
模拟赛 D1T1
显然配对就是左右部图按照标号排序后取左边标号的第 \(t\) 大与右边标号的第 \((|S|-t)\) 大进行匹配。考虑计算配对限制 \(\leq s\) 的方案数 \(g_s\)。对于 \(g\) 做一遍差分就可以得出限制 \(=s\) 的方案数,最终答案就是 \(\sum g_ss\)。考虑对于不同的 \(s\) 分开求。那么现在就是给定 \(s\) 求有多少 \((S_1,T_1,S_2,T_2)\) 符合条件。注意到左部图是从前往后,右部图是从后往前,那么就有一个状态就是 \(f_{i,j}\) 表示左边考虑了前 \(i\) 个点,右边恰好匹配到第 \(j\) 个点的方案数。初始值为 \(f_{0,n+1}=1\)。转移形如 \(4f_{i-1,j}\to f_{i,j}\) 以及 \(f_{i-1,k}\to f_{i,j}\) 要求 \(i+j\leq s\) 且 \(j<k\)。对于第二类转移可以使用前缀和优化。时间复杂度 \(\mathcal O(n^3)\)。
联合省选 2018 D1T3
- 对于 dp 转移为卷积的形式,视作多项式,可以求若干点值。最后用拉插还原(联合省选 \(2024\text{ D2T2}\) 的 \(\mathcal O(3^nn)\) 做法 )
链你直接固定 \(l\) 扫 \(r\) 随便维护一下就行了。大概是正解无关的。
考虑枚举第 \(k\) 大的值,计算有多少个连通块的 \(rk(V',k)\ge lim\) 的方案数 \(g_{lim}\)。对于 \(g_{lim}\) 进行一遍差分后答案就是 \(\sum g_xx\)。此时将 \(a_i\ge lim\) 的视作 \(1\),否则视作 \(0\)。要求连通块中至少有 \(k\) 个 \(1\)。在树上进行 dp 表示 \(f_{u,i}\) 为以 \(u\) 为根的连通块有 \(i\) 个 \(1\) 的方案数,可以做到 \(\mathcal O(nk\min(W,n))\)。
值得一提的是,树上背包第二维枚举子树大小并对 \(m\) 取 \(\min\) 的复杂度是 \(\mathcal O(nm)\)。
我们用 dfs 序分析,注意到一个子树的 dfs 序区间,而 \(\min(siz_a,m) × \min(siz_b,m)\) 相当于跨过两个 dfs 序区间的长度不超过 \(m\) 的区间数量。 注意到所有长度不超过 \(m\) 的区间数量是 \(\mathcal O(nm)\) 的,并且每个区间只会被算一次,在 dfs 序区间对应的点的 lca 处,这显然是 唯一确定的。 时间复杂度 \(\mathcal O(nm)\)。
来自 kradcigam 的 ZR noip 模拟赛 \(10\) 题解。
结合链有 \(50\) 分。据说卡常可以过。注意到转移是卷积形式,可以上生成函数。你最后 \(k\) 是任意的,因而在拓展做法的过程中不需要进行对 \(k\) 取 \(\min\) 的一步。我们还需要一步转化,事实上并不需要差分,直接对 \(g\) 求和就是对的。因此你看成多项式后它是具有可加性的。
对于分开的 \(lim\) 做是没有救的,可以考虑整体 dp,并且在此过程维护答案数组 \(g\)。此处我们定义 \(g_{u,lim,i}=\sum_{v\in\text{subtree}(u)}f_{v,lim,i}\)。对于 \(f\) 而言,由于 \(1\) 的个数那一维度是卷积,因此将其设为自变量 \(x\)。我们想刻画的是多项式 \(f_{u,lim}(x)\)。那么就是先对所有儿子 \(v\) 做卷积,然后给多项式乘上 \(x^{[d_u\ge lim]}\)。然后将儿子的 \(g\) 累加再加上 \(f_{u,lim}\)。转移的瓶颈就在于 \(f\) 的卷积合并。
注意到最后统计答案需要求出来 \(g_{1,lim}\) 的具体系数和。那么对于不同的 \(lim\) 而言,我们只需要知道 \(n+1\) 个点值就可以用拉格朗日插值求出 \(g\)。这样你转移的形式就是 \((u,v)\) 的点值,直接 \(f_v+1\) 相乘到 \(f_u\)。转移都是加和乘,整体维护过程中对于 \(f\) 是前缀乘。可以考虑线段树维护。不难发现,子树内会形成 \(\mathcal O(\text{subtreesiz}(u))\) 个连续段。因此你只需要考虑有意义的合并就行了。整理一下,你需要维护的线段树应该支持:
- 全局赋值 \(1\),全局 \(+1\)。
- \(f,g\) 对应位相加进行合并。
- 前缀乘(区间乘)值 \(x\)。
可以使用线段树维护线性变换的思想(矩阵)来做。记对于 \((f,g)\) 的线性变换为 \((a,b,c,d)\),会将其转化为 \((af+b,cf+g+d)\)。具有结合律的捏,可以线段树做。最后拉格朗日插值还原系数即可。视 \(n,k,W\) 同阶,时间复杂度 \(\mathcal O(n^2\log n)\)。
这里写一下如何拉格朗日插值求系数。\(f(k)=\sum y_i\prod_{x_i\ne x_j}\frac{k-x_j}{x_i-x_j}\) 是基础式。
首先求 \(a_i=\prod_{x_i\ne x_j}\frac{y_i}{x_i-x_j}\)。然后算出多项式 \(g(x)=\prod(x-x_i)\) 的各项系数。此时有 \(f(k)=\sum \frac{a_ig(k)}{x-x_i}\)。多项式暴力乘可以算,暴力除就是考虑除以 \((x-t)\) 的变化。令 \(h(x)=\frac{g(x)}{x-t}\),那么 \([x^i]h(x)=\frac{[x^i]g(x)-[x^{i-1}]h(x)}{-t}\)。可以递推做。
P11024
首先 \(c=0\) 的处理是平凡的,差分一遍判是否被覆盖即可。然后从每个格子来看的话,就相当于最后一次属于颜色 \(b\) 且覆盖位置 \(i\) 的操作必须在这些覆盖它的操作中的最后一个。注意到最后一次染色操作必然是全部保留的,因而染色问题可以倒序处理。对于操作 \((l,r,c)\) 其有效要求在后续操作中与 \(c\) 不同的都被正确的覆盖过了。那么每次我们只需要倒着构造答案。注意到如果同时可以放 \(a,b\) 使得后续都有解,你可以将 \(a,b\) 相邻排。因此当前有多个可选的时候可以随便放一个。在扫的时候,可以设计如下算法:找出当前任意一个可以填的操作,然后对区间打上标记。一个操作可以填当且仅当未被标记的位置与输入的序列 \(a\) 相匹配。然后就有一个显然的 \(\mathcal O(nm)\) 做法。
注意到如果当前这个操作可以放,那么后续都可以放。显然你每标记一个,这个操作的限制就会减少。这启发我们维护一个操作的队列。每次取出队首并执行标记,找到在这一次变得合法的操作,加入到队尾。如果某次队列为空但没填完就是无解。考虑用数据结构优化这个过程。可以放到线段树上,拆分成 \(\mathcal O(\log n)\) 个区间。一个操作可以入队当且仅当所有 \(\mathcal O(\log n)\) 个子区间都是合法的。那么只需要考虑一整个区间的情况。就需要看这个区间除去打上标记的剩余是否都全部相同。先从更新的角度看,一个区间被完整覆盖需要打 tag,其报警子区间均需要被剪断。在剪断的过程中检测当前不合法区间数即可。然后考虑刻画是否已经全部相同的限制,在 pushup 过程中维护信息,更新访问到的线段树节点即可。我愿称之为报警,在完全改为均有标记的标记与在只有一种颜色时进行报警即可。时间复杂度 \(\mathcal O(n\log n)\)。
ARC100F / NOIP2024 bk 模拟赛 #10D
考虑可以不满足条件 \(1\) 的做法是简单的:直接拆贡献,答案为 \(k^{n-m}(n-m+1)\)。现在考虑对于 \(a\) 进行分讨。如果 \(a\) 包含某个 \(k\) 排列作为子串那么一定是没有不符合条件的;重点在于考虑 \(a\) 存在重复与不存在重复的方案计数。先考虑 \(a\) 不存在重复的情况,显然 \(a\) 是什么是不重要的。
算总贡献可先推方案数。先考虑怎么计数,即不考虑匹配 \(a\) 的限制的方案数。那么就可以 dp,状态数是考虑了长度为 \(i\),极长互不相同后缀长度 \(j\) 的方案数 \(f_{i,j}\)。可以前缀和优化到 \(\mathcal O(nk)\)。考虑拓展到算总贡献。再次回顾 \(a\) 元素是什么并不重要的性质,我们可以将其一般化。对于一段长度 \(m\) 的互不相同子段计总数,除以 \(\binom{m}{k}k!\) 就是答案。考虑为什么是对的,每种 \(a\) 都是一样的。对于 \(a\) 存在重复的情况。找到一个重复的位置,在左边计算一下互不相同的方案数。只关心其最长互不相同的前后缀长度 \(l,r\)。时间复杂度 \(\mathcal O(nk)\)。
CF1344E
我们可以考虑二分答案。先考虑判定一个方案是否合法,我们需要找到合理的刻画方式。对于每个点 \(u\) 去考虑,由若干 \((a_i,b_i)\) 表示在 \(u\) 点满足 \(a_i\) 时刻有一辆开往 \(b_i\) 方向的列车。对于这些限制,按照 \(a_i\) 进行排序。如果有相同 \(a\) 但是 \(b\) 不同就显然是非法的。否则,排序之后,考虑相邻两个时间满足 \(b\) 不同的。那么就可以提取出 \(\mathcal O(n^2)\) 对限制,要求在 \((L_i,R_i]\) 的时间区间内对点 \(u_i\) 进行操作。每个时刻你只能做 \(1\) 次操作。然后有一个贪心策略就是按照 \(L\) 进行排序每次删去 \(R\) 最小的限制。然后就有一个 \(\mathcal O(n^2\log^2n)\) 的做法。注意到二分答案是完全不必要的,注意到每个点的限制相当于是在 popback,不会断开已有的限制。你可以直接加入 \(\mathcal O(n^2)\) 对限制,看什么时候变得非法。用堆维护即可。
考虑优化,我们希望减少有效的 \((L,R]\) 对数。你先分析一下,我说的直接就是对的。我们试图从上往下构造将其卡满的例子。显然你会把所有火车的终点放到叶子上,那么令 \(u\) 有 \(k\) 个儿子,令 \(T(n)\) 表示 \(u\) 为子树根时,此时有 \(n\) 个火车在 \(u\) 往下传最多产生多少有效区间。就有一个大概的递推是 \(T(n)=(n-1)T(n/k)\)。在 \(n\) 达到一定量级时 \(k=2\) 是最优的。然后在完全二叉树上你的构造就止步于 \(\mathcal O(n\log n)\) 级别了。既然数量级是对的,我们可以直接暴力找出所有区间。显然这是一个启发式合并的形式,直接做即可。时间复杂度 \(\mathcal O(n\log^2n)\)。
P11355 / T410849
先考虑任意 \(f\) 全部相同且给定一些允许使用的传送器,如何判定是否可达。我们可以在操作间寻找一些兼而有之的操作量,本题可以选择从 \(A-B\) 的值入手。注意到一次变换相当于选定一个合法的 \(c\),将坐标 \(x\) 变换为 \(2c-x\)。此时两者差原来为 \(d=x_2-x_1\),会变换为 \(2(c_2-c_1)-d\)。注意到两者完全对称,可以取相反数。即增加了 \(2(c_1-c_2)\)。 实际操作中就是 \(p,q\) 的顺序可以换。问题转化为是否可以选择若干组数对 \((c_{1,i},c_{2,i})\),由 \(d=A-B\) 变换到 \(0\)。判掉奇偶错误的情况并除以 \(2\) 之后,考虑使用贝祖定理,这要求所有 \((c_i,c_j)\) 的差分值的 \(\gcd\) 是 \(d\) 的因子。上述运算均取绝对值。这样你就可以暴力判了。
注意到 \(\gcd(a,b)=\gcd(a,a+b)\),那么你将 \((i,j)\) 视为一条边,判定所有差分值的 \(\gcd\) 只需要一棵生成树,也就是说顺序是无关紧要的。因此你可以随便打乱顺序然后取相邻数差分的 \(\gcd\)。这样信息量就正确了。可以按照 \(f\) 进行排序,这样能用的传送器就是一个区间,你可以快速求差分数组的 \(\gcd\) 来进行判定。
考虑正解。最大化最小值可以使用二分答案。你发现在上述过程中,跳相邻的数就可以了,这样在有解的前提下也最小化了 \(\max|f_p-f_q|\)。因此二分 \(mid\) 时只需要加入差值 \(\leq mid\) 的相邻数对的差分。线段树求一下这个区间的合法位置的 \(\gcd\)。多组询问怎么做,套个整体二分即可。时间复杂度 \(\mathcal O(n\log^2n)\)。
P11390
\(k=1\) 是矩形面积并。拓展一下可以进行容斥,枚举一个子集 \(S\) 然后计算有多少 \((l,r)\) 符合条件。做类似于春测 T4 的扫描线线段树即可。时间复杂度 \(\mathcal O(2^kkn\log n)\)。
P11391
- 正多边形三角剖分可以转对偶图,其图的形态是树。
我们直接猜测,一条回路与图形的一个子多边形一一对应。进而有一个回路与一个点集一一对应。并且一种合法的顺序就是标号顺序。然后考虑使用更好的刻画方式。考虑对原图 \(G\) 构建对偶图,一个原图的三角形对应对偶图上一个节点,两个节点有边连接当且仅当两个三角形在原图上有公共边。这样建出来的是 \(n-2\) 个点 \(n-3\) 边的树 \(T\)(经典结论)。那么找一下原图的一个环对应对偶图的什么。我们不妨断言一个树上的连通块就是一个环。证明我不会。那么求出来树之后就是简单的树上 dp。现在考虑如何构建 \(T\)。问题在于找出所有的 \((a,b),(b,c),(c,a)\)。其实我们可以采用类似于拓扑排序的方法,不断剪掉多边形的边界来构建,用 set 维护这个过程。时间复杂度 \(\mathcal O(n\log n)\)。
QOJ5098
考虑 \(\mathcal O(nq)\) 的做法:扫描线 \(r\),其 \(l=\max pre_i+1\),其中 \(pre_i\) 表示上一个与 \(i\) 颜色相等的位置。那么令 \(sum\) 表示 \(a\) 的前缀和之后,对于 \(sum_r\) 就减去的是前缀 \(pre\) 最大值 \(mx_r\) 对 \(l-1\) 取 \(\max\) 作为 \(sum\) 下标的结果。如果是不带修的,可以二分找一下取 \(\max\) 的位置。对于每个颜色维护一个 set,每次就是 \(\mathcal O(1)\) 个对于 \(pre\) 的单点修改。前缀最大值状物可以考虑楼房重建线段树维护。然后本题保证了 \(sum\) 是固定的。在此基础上做。
首先 \(pre\) 数组的区间 \(\max\) 是容易维护的。然后考虑在 \([1,r]\) 范围上施加 \(pre\) 对 \(l-1=lim\) 取 \(\max\) 的影响。我们可以维护已经有的信息来达到单侧递归的效果。如果 \(lson\) 的最大值 \(>lim\),那么对右侧是可以直接访问的,然后向左侧进行递归;否则,\(lson\) 的信息就是区间 \(\max\) 减去 \(sum_{lim}\),需要向右侧进行递归。时间复杂度 \(\mathcal O(n\log^2n)\)。
模拟赛 D2T2
【模板】李超树。
QOJ5035
- 线段树的 \(\log\) 在某些情况可以替换为并查集的 \(\alpha(n)\)。
考虑断环为链,先考虑枚举一条边被断开然后成链的情况的暴力。注意到一个关键性质是对于 \([l,r]\) 段内的最大值 \(p\),前缀最大值个数是 \([l,p]\) 的前缀最大值个数,后缀最大值同理是 \([p,r]\) 的。那么找到 \(n\) 的位置后,我们考虑连接值为 \(n\) 的点的两条边一定不会同时被保留,这是因为贡献会被 \(n\) 截断到一侧,那么另一端可以在 dp 过程视为没有贡献的,特殊处理一下就好了。这样只需要跑 \(2\) 次链的情况。
考虑链怎么做。有一个 dp 就是 \(f_{i,j}\) 表示考虑前 \(i\) 个数被划分为 \(j\) 段的最大价值。那么可以按照 \(k\) 为阶段划分状态。可以考虑单调栈维护一下后缀 \(\max\) 的位置。考虑维护一下两个区间 \(w(l,r)\) 的 \(w_1\) 表示前缀最大值个数,\(w_2\) 表示后缀最大值个数。那么扫描线维护一下 \(w_1\) 带上前面的 \(f\),\(w_2\) 同理。\(w_1\) 对于一段后缀是 \(+1\) 的变化。\(w_2\) 是单调栈弹出的时候对前缀 \(-1\)。然后你维护的是 \(\max(w_{1,i},w_{2,i})\)。显然可以分开维护的。然后你只需要做的是 pushback 以及查询全局 \(\max\)。直接线段树就是 \(\mathcal O(nk\log n)\)。
主动想一下并查集。显然你可以维护一个全局加法的 tag 并将前缀加转化为后缀 \(+1\)。那么显然我们只会关心所有的严格后缀 \(\max\) 的点,否则其无法成为全局 \(\max\)。可以使用单调栈维护。并且每次后缀 \(+1\) 可能会导致若干点被删去。直接维护是不好做的,那么考虑维护后缀 \(\max\) 间的差分数组,那么对于一次后缀加,我们需要定位到后缀第一个后缀 \(\max\) 点,并且后续还会更改,可以使用并查集。每次再加可以在差分单点加,然后暴力 pop 一下不再是后缀 \(\max\) 的。全局 \(\max\) 就查询后缀 \(\max\) 这个队首的值即可。时间复杂度 \(\mathcal O(nk\alpha(n))\)。
模拟赛 D2T3
- 有单调性可以考虑其差分。
我宣佈嗯哦哎點哎希的考試題解已經不是題解了!
首先对于一组顺序,其权值为 \(\max(\sum_{j\leq i}a_j+b_i)\)。那么先考虑对于给定的 \(a,b\) 以及 \(k=n\) 做。猜测顺序是按照 \(b\) 从大到小去做。发现这是对的,证明可以考虑邻项交换,这是因为 \(\sum a_j\) 是不降的,对于 \((s_1,s_2),(s_1+k_1,s_2+k_2),k_1,k_2\ge 0\),交换成 \((s_1,s_2+k_2),(s_1+k_1,s_2)\) 一定是不劣的。那么可以对 \(b\) 从大到小排序后求所有 \(k\) 的答案:这样就是选出一个子序列来求,考虑 dp 来做。\(f_{i,j}\) 表示第 \(i\) 个数是选取的第 \(j\) 项,此时仍然是不好做的。考虑从后往前做,\(f_{i,j}\) 表示 \([i,n]\) 中选取的 \(j\) 项的最小价值。这样做的好处是,你观察到 \(a\) 是前缀和状物,这样的操作是永久性的。转移有 \(f_{i,j}\leftarrow\min(f_{i+1,j},\max(f_{i+1,j-1},b_i)+a_i)\)。
首先猜一下 \(k\) 的最优解包含 \(k-1\) 的最优解。
注意到 \(f\) 具有单调性,可以试一下差分数组。那么就是有一个变量 \(tot=0\)。每次执行操作 \(tot\to \max(tot,b_i)+a_i\)。选取长度为 \(k\) 的子序列 \((a,b)\) 然后最小化 \(tot\)。然后 \(\Delta tot\) 其实就是差分数组。那么你贪心一下,维护一个小根堆表示加的量(初始是一个 \(+\infty\))。那么你的过程就是:倒序考虑所有 \(i\);如果满足 \(tot+top\leq b_i\) 就一直执行弹出并将 \(tot\to tot+top\) 的操作;不满足的时候,贪心让 \(top\) 变化为 \((tot-b_i)\)。然后 \(tot\to b_i\),加入 \(a_i\) 到堆中;弹出 \(k\) 个数的时刻的 \(tot\) 即为 \(f(k)\)。 注意最后要设置一个 \(b_0=+\infty\) 的把堆清空。
枚举 \(k\),在每个 \(a_i\) 加入时确定其是否累加入 \(tot\),从而"维持单调递增"仅需确定分界点两侧的值 \(p,q\)。对这个过程做一下 dp 来完成计数。思路类似于 dp 套 dp。那么就有一个状态就是 \(f_{i,j,p,q,t}\) 表示考虑了倒数 \(i\) 个 \(b\) 此时已经弹出了 \(j\) 个数,目前在堆中的钦定被选上的最大值是 \(p\),钦定没被选上的最小值是 \(q\) 的方案数。转移可能需要枚举 \(a_{i+1}\) 进行向后转移。
滚动后空间复杂度是 \(\mathcal O(n^3m^2)\),时间复杂度 \(\mathcal O(n^3m^4)\)。
AT_arc118_e
\(p\) 给定有直接容斥的做法,钦定一个子集 \(S\) 要求 \(S\) 必须被经过,容斥系数 \((-1)^{|S|}\),可以直接 dp,复杂度 \(\mathcal O(n^2)\)。这启示我们去考虑容斥,可以拆贡献到每一条路径上。对于一条路径而言,其可能经过固定的点,但是对于某些行可能不会经过固定点,我们可以选择这一行的 \(p\) 然后视其是否产生贡献。一个性质是考虑每行选出的是 \(p_i\) 作为钦定的,那么 \(p\) 互不相同等价于 \(p\) 单调递增。然后记选出了 \(k\) 个,其中 \(p\) 个使用了未知点,一共有 \(c\) 个未知行,就还需要带上 \((c-p)!\) 的系数。但总的容斥系数还是 \((-1)^k\)。然后你考虑关键点不共行共列的性质,也需要放入 dp。对于这些路径进行 dp。那么就是 \(f_{i,j,k,0/1,0/1}\) 表示考虑到 \((i,j)\) 为右下角的路径,钦定了 \(k\) 个,第 \(i\) 行是否已经有关键点,第 \(j\) 列是否已经有关键点的总贡献。对于 \((-1)\) 的系数而言你每钦定一个关键点就乘上 \(-1\) 进行转移即可。时间复杂度 \(\mathcal O(n^3)\)。
QOJ8226
一个观察是 sift down \(k\) 次之后根节点的值是子树的第 \(k+1\) 大的 \(a\)。
先考虑一下给定 \(S\) 时的操作策略。对于根节点我们会不断 sift down 直到某次操作后会导致 \(S\) 集合中的点不合法。然后这个只与子树有关,所以查询有多少 \(a_x'=y\) 的时候你只会考虑 \(x\) 子树外中在 \(S_2\) 中的点的个数 \(c_2\) 即可,最终答案乘上 \(2^{c_2}\) 即可,修改可以暴力改祖先的信息。然后你考虑就只保留 \(S\) 在 \(x\) 子树中的部分,查询就只在根上做 sift down 操作,往下面做是不必要的。往下面再 sift down 也不会再影响 \(x\),因为这个 \(x\to root\) 的链一定提的很靠上了。注意到再 pop 会导致某个点不合法,进而我们猜测 \(S\) 可以直接改成一堆单元集分开独立跑,这是因为最终导致其停止修改的是个单元集,\(a_x'\) 就是最终这些取 \(\max\)。因此考虑直接求 \(f_{x,y}\) 表示 \(x\) 子树中 \(a=y\) 的操作答案。然后统计答案。此处求 \(f\) 有一个精妙的求法。可以在树上 dfs 所有的 \(x\),可以继承原来的信息。整理一下,需要维护:子树外 \(S_1,S_2\) 的点数;子树内有多少在 \(S_2\) 但是不在 \(S_1\) 的点满足 \(f<z\),有多少 \(f=z\)。需要查询 \(S_1\) 中 \(f_{x,S_i}\) 的最大值 \(t\)。小小讨论一下就好了。把所有询问离线到 \(x\) 后使用带删堆和树状数组维护,时间复杂度 \(\mathcal O(n^22^n)\)。
QOJ5168
考虑直接维护极大的同色连通块,我们要求一个连通块只会被删去 \(1\) 次。这样一共就是 \(\mathcal O(m)\) 个连通块。那么考虑维护每个连通块的颜色,大小,根节点的 dfs 序。那么考虑染一个子树为 \(y\) 颜色。如果 \(col_{fa(x)}\ne y\),只需要将所有 \(x\) 子树内的连通块删除。否则不仅要删除,还要考虑与父亲连通块的合并。随便用一个带 \(\log\) 数据结构来维护区间推平单点查询。在删除过程中,计算一下被删除的连通块大小和即可。时间复杂度 \(\mathcal O(n\log n)\)。
模拟赛 D3T2
考虑 \(typ=0\) 的情况。直接 dp,设 \(f_i\) 表示 \(i\) 结尾的划分方案数。那么要求分出来的一段有 \(len\ge \max\)。可以使用 cdq 分治,每次考虑新划分的区间 \([l,r]\) 在 \(l\in[L,mid],r\in[mid+1,r]\) 的贡献 \(f_{l-1}\to f_r\)。那么考虑 \(a_i\) 在左半区间的后缀 \(\max\) 与右半区间的前缀 \(\max\),分别为 \(suf,pre\)。就要求 \(r-l+1\ge \max(suf_l,pre_r)\),可以拆开 \(suf,pre\),计算每个位置作为 \(\max\) 时的贡献。分别可以用后缀和优化与差分做到 \(\mathcal O(n\log n)\)。
考虑 \(typ=1\),可以计算不合法变为合法的划分数量。那么需要跑一遍后缀的划分,然后考虑区间 \([l,r]\) 满足在原序列有 \(len<\max\),但是修改某个 \(x\) 之后就满足 \(len>\max\)。此时对于 \(ans_x\) 就应该加上 \(f_{l-1}g_{r+1}\)。显然需要修改的 \(x\) 就是 \(\max\)。那么判定就要求 \(\text{secmax}\leq len\)。同样可以分治考虑这些区间。对于限制 \(r-l+1\ge\max(x_l,y_r)\) 可以转化为 \(r\leq l+x_l-1\) 且 \(l\leq r-y_r+1\)。其中 \(x,y\) 使用 \(\text{secmax}\) 或者 \(\max\) 由双指针的范围决定。可以使用二维偏序加一点容斥的思想。时间复杂度 \(\mathcal O(n\log^2n)\)。
模拟赛 D3T1
爆搜每一位是否进位然后讨论一下即可。时间复杂度 \(\mathcal O(T2^{\lg n}\lg^2n)\)。
P9393
见到赋值,可以考虑倒序的思想。我们先想,如何判定生成的恰好是 \(S\),发现可以改为 \(S\) 中均为 \(1\) 即可。然后考虑所有操作。现在考虑判定对象所有 \(1\) 构成的集合 \(S\)。注意到是赋值的话,可以从后往前填操作序列,你发现对于某个操作 \(T\),如果 \(i\in S\) 且 \(T_i=1\),对于 \(T_i=0\) 的要求 \(i\notin S\)。此时可以将 \(T\) 置于操作序列的末尾,并且将 \(T_i=1\) 且 \(i\in S\) 的所有 \(i\) 移除。如此往复,直到无法操作时,判定最终 \(S\) 是否为初始状态 \(x\) 中为 \(1\) 的位置集合的子集即可。
那么只需要考虑对于所有 \(S\) 最终的形态 \(f_S\) 即可,然后对于询问 \(x\) 求其子集 \(\max\) 即可。求出来 \(f\) 之后可以转置 \(f\) 后求高维前缀和做到 \(\mathcal O(m2^m)\)。问题来到求 \(f\)。只需要考虑在某一步中消尽量多的,\(g_S\) 表示消掉的。转移就是 \(f_{S\oplus g_S}\to f_S\)。求 \(g\) 也是高维前缀和状物,容易预处理。因此总时间复杂度 \(\mathcal O(m2^m+n+q)\)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效