NOIP 前随机选做
CSP 奋战两小时 arena 死活调不出,奇耻大辱哦。
不如加练。
20241028
CSP-S2024 T4
很需要大脑清醒的一道题。
自底往上对于每个询问 \(\mathcal O(\log n)\) 做是没有救的,大概就是从 \(u\) 开始往上跳,维护可以赢的确定的单点以及不会被已有点击败的未确定点的后缀。
显然是要拆贡献,考虑对于所有 \(m=\lceil\log_2t\rceil\) 的所有 \(t\) 求出答案。注意到对于一个未确定的点,不会因为它导致某个确定点被淘汰,因为总可以调整它的能力值使得定点是赢的。对于 \(m\) 可以按顺序逐个加入叶子节点 \(u\),我们称确定前缀 \(i\) 的版本叫时刻 \(i\)。注意到限制相当于是越来越严的,所以一个点如果在某个时刻无法成为最终赢家,那么在后续时刻也不会赢。因此每个点作为确定点可以作为最终赢家的时刻是一段区间;作为非确定点时,如果其确定无法胜出,一定是因为往上走的过程中被一个对方确定的赢家淘汰掉的,因此其造成贡献的时刻也是一段区间。线性做法大概就是要处理出所有点作为两类点分别造成贡献的区间,差分合并统计答案即可。
考虑对于所有 \(m\) 分开处理,如果可以做到 \(\mathcal O(2^m)\) 处理每个 \(m\) 的子问题,整个问题就是 \(\mathcal O(Tn)\) 的。
关键的信息是子树 \(o\) 的胜者能力值是否确定。注意到对于一个子树 \(o\),对于 \(a_i\) 可以和 \(m\) 取 \(\min\)。每次其胜出的能力值只有可能是一个定值(即一个确定的值通过确定的路径胜出)或者是 \(\ge R_o\)。考虑逐个加点来维护这个过程,维护 \(f_o\) 表示子树 \(o\) 的胜者或者 \(\ge R_o\) 都是可以取到的,分别记为 \(-1\) 以及 \(a_{\text{winner}}\)。注意到一个 \(f_o\ge 0\) 当且仅当一个确定值的点的一条路径是无论如何都会获胜的,所以不会再更改,每个 \(f\) 至多更新一次,因此暴力更新 \(f_o\) 的复杂度是均摊正确的。进而,我们考虑 \(f_o\) 确定时可以删去哪些节点,让这些新更新的节点给由可能转为不可能的兄弟节点 \(v=u\oplus 1\),给子树 \(v\) 打上当前时间的标记,表示这个子树自此开始无法成为最终赢家。注意到这个标记其实只需要在最后 \(\text{pushdown}\) 到每个叶子节点上,所以可以线性更新。
总而言之,就是考虑何时子树胜者确定,时间复杂度 \(\mathcal O(Tn)\)。另一种线性的做法是自顶往下维护赢家的约束,在结束一个子树的递归后考虑另一个子树的赢家胜者权值的下界即可。
ZR3004
注意到任意顺序消都是对的,考虑一个串消到最简的形式一定是一段固定长度的 \(01\) 交错段,可以线段树维护。区间取反也是容易打标记维护的,信息的形式显然就是这个最简串的开头 \(st\) 以及长度 \(len\),操作 \(1\) 是容易维护的。注意到对于查询是没有单调性的,因为我们要判定的东西是 \([l,r]\) 中是否存在 \(l<i\leq r\) 使得 \([l,i]\) 是可以消完的。考虑信息合并,如果 \([l,\text{mid}]\) 存在前缀可以消完,那么 \([l,r]\) 自然也存在;我们需要考虑是否存在 \(x\) 使得 \([l,\text{mid}]\cup(\text{mid},x]\) 是合法的。那么我们希望维护右侧所有前缀的信息,\([l,\text{mid}]\) 只会提供一个信息。注意到所有前缀消完后,最简形式中,设 \(1\) 开头的最长长度为 \(m_1\),\(0\) 开头的最长长度是 \(m_0\),那么可以证明 \([0,m_1]\) 以及 \([0,m_0]\) 都是可以取到的。那么对于左侧去判右侧是否合法是容易的,使用线段树二分即可做到 \(\mathcal O(q\log n)\)。另一种思路是将奇数位取反后 \(0\) 看成 \(-1\),这样可以维护所有前缀和的值域 \([mn,mx]\),二分过程是类似的。
CF1930F
考虑全体 \(\text{or}\) 上 \(x\) 就是在对于 \(x\) 中不为 \(1\) 的所有位求极差。先想 \(q=2\) 的做法:对于给定的 \(a,b\),不妨设 \(a\ge b\),那么我们希望 \(a_i=1,b_i=0\) 的均计入贡献,此时的答案就是 \(a\text{ and rev}(b)\)。注意到 \(a,b\) 大小关系是不确定的,因此还需要考虑 \(\text{rev}(a)\text{ and }b\)。拓展到 \(q\) 很大,我们希望在插入时就计算好钦定 \(b\) 为新加入的 \(x\) 的影响,我们可以只考虑 \(a\text{ and rev}(b)\) 的情况,因为对于另一种情况可以所有数全部按位取反对称地做一遍。那么现在就是要维护一个数集:支持插入 \(x\),查询 \(S_i\text{ and } y\) 的最大值。对于查询操作,直接从高往低按位贪心取即可;对于修改操作,注意到 \(\sum n\) 是有限制的,因此可以考虑值域相关做法,维护 \(f_S\) 表示是否存在以 \(S\) 为子集的数,每次直接枚举 \(p\subseteq x\),记忆化搜索即可,向下递归只考虑 \(|p|=|x|-1\) 即可。时间复杂度 \(\mathcal O(n+q\log n)\)。
CF2035E
考虑 \(f(a,b)\) 表示 \(a\) 次操作 \(1\),\(b\) 次操作 \(2\) 的最大伤害值。显然操作 \(1\) 应该都是尽量连续的 \(k\) 次,令 \(t=\min(b,\lfloor\frac{a}{k}\rfloor)\),不难整理得 \(f(a,b)=a(b-t)+k\frac{t(t+1)}{2}\)。这样的操作代价是 \(w(a,b)=ax+by\)。题意就是求最小的 \(w(a,b)\) 使得 \(f(a,b)\ge z\)。先注意到单次的复杂度应该是与 \(\sqrt z\) 有关的,并且 \(f\) 的计算式是 \(t^2,a,b\) 有关的,考虑整除分块的方向。对于一个确定的 \(b\),可以考虑二分找到最小的 \(a\) 使得 \(f(a,b)\ge z\),对于 \(a\) 也同样对于上升的 \(b\) 不减。根据数据范围的提示,不难猜想 \(\min(a,b)\leq\mathcal O(z)\)。直接取上界 \(4z\) 然后枚举 \(\min(a,b)\) 进行二分即可。时间复杂度 \(\mathcal O(Tz\log z)\)。
CF2035F
考虑操作无序,那么可以先做 \(-1\) 调整到全 \(\leq 0\),再做 \(+1\)。注意到 \(n\leq 2000\),所以考虑枚举 \(ans\bmod n\) 的值 \(m\)。那么相当于有前若干个位置必须额外操作一次。然后考虑二分答案 \(mid\) 表示最小的完整轮数使得整棵树可以在 \(n\times mid+m\) 的操作内合法。注意到我们可能需要对奇偶分开做,因为可能出现一个位置无法正确调整的情况,对于不同奇偶的 \(mid\) 是不存在单调性的。考虑 \(f_u\) 表示上面至少需要补充多少次操作才能使 \(u\) 变成 \(0\),转移是简单的,最终就是判定是否有 \(f_R=0\)。时间复杂度 \(\mathcal O(n^2\log V)\)。
20241029
ZR3053
谁写的题面啊/fn。考虑转化原问题为 \(s\) 往下走和 \(t\) 往上走的两个独立问题。在一个问题中一个点是合法的当且仅当存在一种合法方案使得 \(s\) 经过了这个点且所有路径均是点不相交且合法的。我们枚举这个点 \(u\),令其是第 \(x\) 层的,事实上我们发现只与 \(x-1\) 层的方案有关,可以在上一层把路径分割,只要存在 \(x-1\) 层和 \(x\) 层之间的路径方案,使得 \(u\) 与上一层的一个可以从 \(s\) 传输的节点 \(v\) 之间存在边 \((u,v)\) 连接,则 \(s\) 到 \(u\) 有合法的方案。因此可以按序从小到大遍历 \(x\)。在每一层考虑每一个点 \(u\),在图上删去其它不可由 \(s\) 到达的点连向它的边然后跑二分图完美匹配。为了保证复杂度正确,每次只需修改该点的连边。时间复杂度 \(\mathcal O(nmk\sqrt k)\)。
UOJ840
字典序可以考虑调整法进行分析。 难点在于判定 \(S\) 是否合法。
考虑计数,注意到一个显然的事情:最后一个 \(c=1\) 的真实值必然是 \(n\),\(S\) 是否包含这个并无所谓。这启示我们按照当前前缀中最后一个未被确定的 \(c_i=1\) 来划分状态。而对于 \(c=0\) 的位置一定是单调递增的,否则考虑交换后字典序不劣。分析前缀最大值的情况,考虑一个必要条件:对于所有 \(c_i=1\) 且 \(i\in S\) 的所有 \(i\) 构成的集合 \(T\subseteq S\),对于任意的 \(i<j,i\in T,j\in S\),如果 \(b_i>b_j\) 且交换 \(b_i,b_j\) 生成的 \(c\) 方案仍然与输入的 \(c\) 相同,那么这样的 \(S\) 一定是非法的,否则交换后字典序是不劣的。现在考虑 \(b\) 能否是字典序最小的方案,依然对于 \(c_i=1\) 的 \(i\) 分析,令下一个前缀最大值的位置是 \(nxt_i\),不存在则为 \(n+1\)。那么相当于要求 \([1,nxt_i)\) 的最大值为 \(b_i\)。 现在要求 \(j\in S,i<j,b_i>b_j\) 交换后不符合条件,即生成的 \(c\) 不同。自然想到考虑 \([1,nxt_i)\) 的次大值为 \(k\),注意到 \(b_j\ge b_{nxt_i}\) 或者 \(b_j\leq k\) 都是无用的,会导致 \(c\) 的改变。那么考虑当且仅当 \(k<b_j<b_{nxt_i}\) 的 \(j\) 可以与 \(i\) 交换且不改变 \(c\) 的取值。也就是说,对于某个前缀最大值 \(i\),如果 \(i\in S\),就可以推出所有 \(k<b_j<b_{nxt_i}\) 的 \(j\) 必须满足 \(j\notin S\)。用构造的思想,这个条件是充分的,每次可以放的最小值一定是符合条件的。
考虑计数,这个是在值域上,对于每个前缀最大值而言就会限制若干两两不交的值域区间 \((l_i,r_i)\) 表示如果 \(c_i=1,i\in S\),就必须有此值域区间的 \(b_j\in(l_i,r_i)\) 满足 \(j\not\in S\),这些值域区间以及限制是互不干扰的。注意到 \(c\) 是关键的,之前说了 \(c=0\) 的位置必然单调递增,所以可以考虑对 \(c\) 为 \(0\) 的位置做 dp。设计 \(f_i\) 表示 \([1,i]\) 中选取 \(S\) 且 \(i\in S,c_i=0\) 的方案数。转移考虑上一个为 \(c_j=0,j\in S\) 且 \(b_j<b_i\) 的进行转移,转移有 \(f_j2^{w(b_j,b_i)}[b_j<b_i]\to f_i\)。其中 \(w(L,R)\) 表示有多少限制区间 \((l_i,r_i)\) 被 \([L,R]\) 完整包含,表示这些未决策的 \(b\) 会与对应的前缀最大值位置一起做决策,系数是 \(\times 2\),暴力可以做到 \(\mathcal O(n^2)\)。而限制区间不交,所以可以树状数组优化转移,时间复杂度 \(\mathcal O(n\log n)\)。
AT_codefestival_2016_final_i
矩阵问题中神秘二分图 trick 的应用。
注意到对于大部分情况,每个位置只有可能变换到 \(4\) 种位置上。对于 \(n,m\) 为奇数的情况,可以对中间的列或者行进行特判,可以删去影响奇偶性的部分,也可以转化到 \(n,m\) 均为偶数的情况。考虑将 \(n\times m\) 的矩阵分成四块,进行标号的原则是每个位置可以变换到的位置,每个等价类的大小恰好为 \(4\)。先考虑同等价类中存在字符相同的方案数,无论奇排列还是偶排列都存在方案可以置换出来,因为对于某种本质不同的方案是存在奇偶性不同的排列的,这样的方案数就是多重集组合数,称这样的等价类是平凡的。
进而考虑等价类内部互不相同的情况:考虑对于每种等价类,其四个位置最终都走到了 \(p_1,p_2,p_3,p_4\),那么考虑每次交换就是对排列进行置换,并且让矩阵的其他位置不变,那么每行每列的交换次数必定为偶数,就会产生偶数次 \(\text{swap}\),最终的方案只能是偶排列,因此只有 \(12\) 种操作是自己内部转不影响其他的,可以直接乘上。考虑某行某列的交换次数为奇数的情况,这样会导致某对字母被最终交换,并且这样做是奇排列,需要考虑与其他非平凡等价类的复合。经典套路,考虑建立二分图,左部图是行,右部图是列。对于所有非平凡等价类的左上角代表元 \((r,c)\) 连边 \(L_r\to R_c\),然后确定一个点权表示对应列或者行是否进行 reverse,每条边就代表一个等价类,对端点点权进行 \(\text{xor}\) 得到边权。然后由边权是 \(0/1\) 来确定排列的奇偶性,每种非平凡排列确定奇偶性后都是 \(12\) 种。注意到对于一个连通块,只需要确定一个生成树的边权即可,因此一个连通块的方案数就是 \(2^{|V|-1}\)。并查集维护容易做到 \(\mathcal O(nm\alpha(nm))\)。
UOJ542
首先显然序列 \(S\) 的作用就是得到一个矩阵 \(w_{x,y}\) 表示 \(S_i=x,S_{i+1}=y\) 相邻对数的个数,有一个比较朴素的 \(\mathcal O(2^mm^2)\) 做法,没有比较好地利用代价的性质,就是 \(f_S\) 表示 \(S\) 集合放置了前 \(|S|\) 个的最小代价,枚举 \(i\) 新加入,此时需要对于所有 \(j=1,2,\cdots,m\) 都遍历一遍计算代价。考虑优化到 \(\mathcal O(2^mm)\)。注意到代价是求和式,因此可以拆下贡献到每个元素上,每个元素就有一个贡献系数。转移的代价是 \(g_{S,i}\) 表示已经有 \(S\) 被放置,往后面接 \(i\) 的代价,然后你发现暴力计算是需要对所有 \(j\) 都计算的,考虑优化就是发现对于两个相近的集合 \(S,T\) 使得 \(T=S\cup\lbrace x\rbrace\),这个代价的变化是可以 \(\mathcal O(1)\) 计算出的。注意到对于空间而言,可以只保存 \(i\notin S\) 的所有状态。因此总时间空间复杂度均为 \(\mathcal O(2^mm)\)。
20241030
主播啥时候做了一车 LOJ 的题啊????昨天晚上搬洛谷上了,咋一点印象都没了,如做了。
ZR3065 / QOJ1286
场切了。
一条路径最优显然就是按照其经过的所有点构成的路径上的 \(a\),从大到小排序得到一个字符串 \(s\),此时 \(s\) 的字典序最大时是最优的。考虑没有障碍时怎么做:显然可以 dp,\(f_{i,j}\) 表示当前从 \((1,1)\) 走到 \((i,j)\) 时的最优字符串,转移就考虑 \(f_{i-1,j}\) 以及 \(f_{i,j-1}\) 哪个字典序更大,然后再插入 \(a_{i,j}\)。考虑有障碍怎么做,路径的形式就形如两个 \(\texttt{L}\) 形拼起来,再处理一个 \(g_{i,j}\) 表示 \((i,j)\) 走到 \((n,n)\) 的最优字符串,考虑左下角的 \(\texttt{L}\) 形,枚举其第一次到达直线 \(x=x_r+1\) 的位置 \(1\leq i<y_l\),可以拼接 \(f_{x_r,i},g_{x_r+1,i}\),做一个前缀 \(\max\) 就可以只访问 \((x_r+1,y_l-1)\) 位置的字符串,对于 \((x_l-1,y_r+1)\) 的倒 \(\texttt{L}\) 形同理做后缀 \(\max\)。注意到直接使用字符串维护是很慢的,考虑对于 \(f,g\) 都建立主席树,每个版本都基于可能的两个前驱中的一个插入 \(a_{i,j}\),现在考虑比较字典序的过程,可以用哈希维护每个区间的哈希值来判定两个串在值域区间上是否相同,然后可以二分找到第一个不同的位置。实现上,对于拼接的串,其访问的形式是一个 pair<int,int>
表示 \(f,g\) 对应的根。总时间复杂度 \(\mathcal O(T(n^2+q)\log n)\)。
P10208
很二分图匹配,先扔到二分图上分析一下。不妨设所有人已经按照 \(a\) 进行排序,那么现在就是要做一个二分图完美匹配,左部图向右部图连,那么会让每个人 \(i\) 会向 \([l_i,i)\cup(i,n]\) 进行连边,其中 \(l_i\) 是最小的 \(a_j\ge b_i\)。运用 Hall 定理进行分析,我们要求 \(|S|\leq |N(S)|\)。很强的性质是,无论如何都有 \(L_i\to R_j,j>i\) 的边。那么取 \(S\subseteq L\) 的时候, \(N(S)\) 必然包含 \(R_j,j>i\) 的所有点,由于连边形式都是一段区间,那么 \(i\in N(S)\) 的必要条件就是 \(i+1\in N(S)\),所以只需要判定 \(R_i\) 是否在 \(N(S)\) 之中,且在 \(S\) 直接取 \(i\) 的后缀时就可以判定 \(|S|\) 与 \(|N(S)|\) 的关系。判定条件就变为是否存在 \(j>i\) 使得 \(b_j\leq a_i\),如果不存在,就要求 \(b_i<a_{i-1}\) 表示 \(L_i\) 是可以匹配上的,同时需要关心后缀的 \(b_{\min}\) ,可以做到 \(\mathcal O(n)\) 判定。考虑写成线段相交的形式,两组线段 \([b_i,a_i],[b_j,a_j]\) 相交就代表可以匹配,那么不存在匹配就是考虑线段 \([b_i,a_i]\) 相当于独立存在,即对于 \(n\) 个线段,判定是否存在某条线段不与别的线段相交。回到原问题上,对于每个线段,向左向右分别找到第一个与其相交的线段 \(L_i,R_i\),那么就可以在二维平面上插入矩形 \(x\in(L_i,i],y\in(i,R_i]\) 表示这个矩形内的点 \((x,y)\) 代表区间 \([x,y]\) 都是不合法的,即这些区间都包含了 \([b_i,a_i]\) 这个区间使得这个区间是不与其他区间存在交集。二维数点是容易,找 \(L_i,R_i\) 可以通过线段树维护,时间复杂度 \(\mathcal O(n\log n)\)。
P7565
注意到重心的移动只能是一条链上,并且 \(|S|\equiv 1\pmod 2\) 时一定有且仅有唯一的带权重心,恰好是在一个关键点上。考虑确定下这条链可以更新哪些 \(ans\)。一个作为重心的判定是子树中关键点数量的最大最小,另一个判定就是这个数量 \(\leq \frac{|V|}{2}\),可以直接改成 \(=\) 并且在最后答案统计时做一遍前缀 \(\max\)。树上路径问题可以直接点分治进行处理,枚举链端点的子树内能挂 \(k\) 个点,那么要求另一个端点也可以挂 \(k\) 个点,然后需要最大化链的长度。直接逐个子树进行处理,每次更新一下后缀 \(\max\) 即可。注意,单链可以作为答案。时间复杂度 \(\mathcal O(n\log n)\)。
ZR3066 / QOJ983
问题等价于计算 \(0\leq x<y<n\) 且 \(m\mid (y-x)(x+y)\) 的数对 \((x,y)\) 个数。考虑枚举 \(\gcd(y-x,m)=d\),令 \(f(d)\) 表示 \(d\mid y-x,d\mid m,\frac{m}{d}\mid x+y\) 的数对 \((x,y)\) 个数;\(g(d)\) 表示 \(\gcd(y-x,m)=d,\frac{m}{d}\mid x+y\) 的个数。那么就有:\(f(x)=\sum _{y\mid x}g(y)\),可以莫比乌斯反演得到 \(g(x)=\sum_{x\mid y}f(y)\mu(\frac{y}{x})\),可以直接枚举所有的 \((x,y)\) 对数,因为 \(m\leq 10^9,T\leq 5\),因此需要枚举的总量是可以接受的,单次的上界小于 \(3\times 10^4\)。问题就来到:给定 \(a,b\),计算 \(a\mid y-x,b\mid y+x,0\leq x<y<n\) 的个数。令 \(y-x=ap,y+x=bq\),就可以得到 \(x=\frac{bq-ap}{2},y=\frac{bq+ap}{2}\),当然是不好计算的。考虑把除以 \(2\) 去了,令重新称原来的 \(p\) 为 \(p'\),原来的 \(q\) 为 \(q'\),枚举 \(c,d\) 表示 \(p,q\) 的奇偶性,就设 \(p'=2p+c,q'=2q+d\),\(c,d\in\lbrace0,1\rbrace\)。那么就有 \(x=bq-ap+\frac{bc-ad}{2},y=bq+ap+\frac{bc+ad}{2}\),显然需要 \(bc,ad\) 同奇偶,并且 \(p,q\ge 0\)。注意到 \(p\ge 0\),因此 \(x\leq y\) 的限制自然成立,只需要最后减去 \(x=y\) 的情况即可。现在考虑 \(0\leq x,y<n\) 的限制,重新令 \(x=bq-ap+k_1,y=bq+ap+k_2\),这样给予了 \(bq-ap\ge -k_1,bq+ap+k_2<n\)。考虑枚举 \(p\) 的取值 \(i\),这样 \(q\) 的上下界都是 \(\lfloor \frac{xi+y}{z}\rfloor\) 的形式,最终就是一个求和。使用类欧算法可以做到单次计算 \(\mathcal O(\log V)\),可以通过。
P6313
先考虑 \(P=1\) 怎么做。我们发现训练营时段 \([l_i,r_i]\) 相当于限制某本护照必须在 \(<l_i\) 的时间获得,并且这些全局的互不相交的区间限制了一些时间允许申请护照。考虑 \(f_S\) 表示获取 \(S\) 集合中的护照的最小时间,转移枚举 \(i\in S\) 表示其是最后一本获得的,构造方案就是要记录前驱,求出这个路径。由这个状态,\(P=2\) 就是拆成两个集合各自找方案,\(P=1\) 就要求的是全局状态合法,由此构造方案。现在细节来到 \(\text{dp}\) 的转移。
考虑由当前状态向外转移,枚举 \(i\notin S\) 那么就是要找最小的 \(nxt\) 表示护照 \(i\) 的申请时间。理想情况显然就直接让 \(nxt=f_S\) 了,但这样没有考虑所有 \([l_i,r_i]\) 的限制。先枚举 \(i\),然后不断调整 \(nxt\)。如果 \(nxt\) 落在了某个 \([l_i,r_i]\) 之中,那么就需要调整到 \(nxt\to r_i+1\);不然,还要考虑申请了 \(i\) 导致无法参加某个训练营,即 \(nxt+t_i\ge l_j\),其中 \(j\not\in S\) 或者 \(j\in S\) 且 \(r_j\leq nxt\),分别表示还未申请以及护照不在手中,暴力循环调整 \(nxt\) 直到其符合条件,复杂度最劣是 \(\mathcal O(2^nn^3)\),因为按照时间排序后,两种限制第一个不满足的分别记为 \(x,y\) 的话,暴力找每次都是 \(\mathcal O(n)\),共需要最多 \(n\) 轮调整 \(nxt\) 直到其可以转移或者宣告转移不合法;考虑优化:由于 \(nxt\) 在不断增加,所以找到的 \(x,y\) 也是不断增加的,可以双指针维护,内层的 \(x,y\) 移动可以做到总共 \(\mathcal O(n)\)。注意到我们并没有用好 \(t_i\) 相互的性质,考虑按照 \(t\) 排序后,\(nxt,x,y\) 所有都是在往前移动的,所以可以一起处理。注意最终转移还需要判 \(f_{S\cup\lbrace i\rbrace}<l_i\),否则不满足题意。时间复杂度 \(\mathcal O(2^nn)\)。
萌熊 T4
点分治模板题。对于每个 \(v\) 处理出到达分治中心允许的最大的 \(D\) 以及 \(a_v\) 本身,之后简单二维数点即可。时间复杂度 \(\mathcal O(n\log^2n)\)。
萌熊 T3
特殊性质 A 就是 \(\max(a_i-a_{i-2})\),可以考虑奇偶构造。注意到一个环对应的值域必然是一个子区间,那么可以处理出每个环的大小后进行爆搜。\(n\leq 150\) 可以通过。
P5371
麻将题的常见套路,考虑尽量放 \((i,i,i)\) 而不是 \((i,i+1,i+2)\),因为后者如果多于 \(3\) 次就可以拆成一堆 \(3\) 个的单点 \(+3\),所以我们向后转移时只关心这个位置 \(\bmod 3\) 的值,因为这样会导致向后两个位置被减去这个位置模 \(3\) 的值。考虑直接对着这个设计状态,\(f_{i,j,k}\) 表示前 \(i\) 小的,放了 \(j\in\lbrace0,1,2\rbrace\) 个 \((i-1,i,i+1)\),\(k\in\lbrace0,1,2\rbrace\) 个 \((i,i+1,i+2)\) 的合法方案数。这个是双射,直接计数就对了。转移考虑确定 \((i+1,i+2,i+3)\) 放多少个,并且同时确定 \(i+1\) 的最终取值,枚举每个状态可以 \(\mathcal O(1)\) 转移。注意到如果没有 \(k_i\) 的限制,转移是没什么限制的,直接矩阵快速幂加速即可,然后得出当前的状态。暴力决策每个有限制的 \((k_i,a_i)\) 进行转移即可。预处理出所有矩阵,然后矩阵快速幂时使用向量乘矩阵的常数会更小。
CQ 神秘模拟赛 T2
\(n\leq 10^5,m\leq 2\times10^4\)。
先考虑双射,判定一个染色方案能否由原来的方案操作得到。注意到很重要的性质是删的过程,如果给颜色之外附上一个属性表示下标,在染色过程中同时把下标染过去,那么相当于直接把被染的位置删了,我们是不关心长度的。显然下标之间的相对顺序不会改变,那么同理,这些颜色我们也不会改变,我们也可以宣称一个颜色连续段的下标也是同一个。因此我们断言,对于新序列 \(b\),考虑其缩连续段得到的相邻元素两两不同的序列是 \(d\),那么我们宣称 \(b\) 合法当且仅当 \(d\) 是 \(c\) 的子序列。充分性的构造是容易的,必要性上面说了。
考虑对缩完后的序列 \(d\),有多少种拓展的办法得到 \(b\)。其长度为 \(k\) 时,就需要计数 \(x_1+x_2+\cdots+x_k=n\) 的正整数解个数,这个是 \(\binom{n-1}{k-1}\),运用 \(\text{Lucas}\) 定理可以 \(\mathcal O(1)\) 计算其模 \(2\) 的值。那么此时我们关心的就是本质不同子序列计数,需要记录其长度并且要求两两相邻元素互不相同。考虑基于子序列末尾的 dp,每次加入一个元素 \(c\),我们更新 \(c\) 的信息,即 \(f_{i,j}\) 表示长度为 \(i\),\(j\) 结尾的本质不同子序列个数模 \(2\),转移有:\(f_{i,c}=\sum_{c\ne j}f_{i-1,j}+[i=1]\)。可以对于每个 \(j\) 把所有 \(i\) 存成 bitset
,这样复杂度就是 \(\mathcal O(\frac{nm}{w})\)。
CQ 神秘模拟赛 T4
\(n\leq 10,c_i\leq 10,m\leq 300\)。
注意到 \(c\) 的值域只有 \(10\),所以可以考虑直接枚举每行的状态 \(S\),注意到合法的 \(S\) 只有 \(\binom{18}{9}=48620\),而 \(m\) 也只有 \(300\)。所以直接压缩 \(f_{i,S,j}\) 表示前 \(i\) 行该行状态 \(S\) 总和 \(j\) 的方案数甚至是正确的。转移考虑对于 \(T\),我们关心的每种值类似于轮廓线的东西,就是一个高维的包含关系。所以我们只需要做高维后缀和即可转移。
P10764
考虑拆贡献到每个位置上,求出所有情况下的 \(\min(\text{premax},\text{sufmax})-h_i\) 的和,可以转化为所有情况下 \(\text{premax}+\text{sufmax}-\max(a)-h_i\) 的和。可以接着拆贡献,所有情况下 \(-h_i\) 的和是平凡的,考虑怎么求所有情况下 \(\max(a)\) 的和。直接线段树优化 dp 即可,维护 \(f_{i,j}\) 表示前 \(i\) 个位置最大值为 \(j\) 的方案数,离散化后线段树支持一些操作即可。\(\text{premax}\) 只需要动态维护一下当前的和,具体的给第 \(j\) 个位置带上系数表示原来的值即可,\(\text{sufmax}\) 只需要倒着做一遍。转移时考虑这一位填什么即可,时间复杂度 \(\mathcal O(n\log n)\)。
另一种做法是考虑转化为 \(01\) 的 trick,对于所有 \(x\) 将 \(>x\) 的视为 \(1\),\(\leq x\) 的视为 \(0\)。对于所有情况下的 \(1\) 个数进行求和,再对所有 \(x\) 将这个和累加就是最终结果。考虑一个位置的水位是 \(1\) 当且仅当 \([i,n]\) 以及 \([1,i]\) 中都存在 \(1\)。依旧拆贡献到每个位置上。那么相当于每个位置有 \(a,b\in\lbrace0,1\rbrace\) 可以选择。如果存在只能选 \(1\) 的位置:那么考虑只能选 \(1\) 的位置中最左边在 \(L\),最右边在 \(R\),那么 \([L,R]\) 无论如何选都会计入贡献;考虑 \([1,L-1]\) 中有前缀选了 \(1\),\([R+1,n]\) 必须有后缀选了 \(1\)。那么考虑到每个位置上,就是计算一下对于前面部分,假如说是一个 \(i\in[1,L-1]\),前缀有 \(x\) 个可选 \(1\) 的位置,造成贡献的方案数是 \(2^i-2^{i-x}\),后缀同理可以计算。线段树扫描线的时候就相当于一个区间乘,当然是可以维护的。如果不存在只能选 \(1\) 的位置,维护的就是 \(2^{n-x-y}(2^x-1)(2^y-1)\),把式子拆了,维护过程也是类似的。写起来一大堆,细节较多。时间复杂度 \(\mathcal O(n\log n)\)。
20241031
ZR3061
将单点也视为实链。考虑静态问题怎么做,不难发现对于一条实链而言,我们要求链底是最后操作的,其他非链底的顺序可以任意调整;并且对于一条实链,我们最终将其染色的时间就是链底的操作时间。那么我们要求对于这条实链,链底的操作时间,必须早于,其父亲所在实链的链底,的操作时间。由此可以建立一棵重构树,\((u,fa)\) 即要求 \(fa\) 的操作时间早于 \(u\),那么放置的顺序数量显然就是这棵树的拓扑序,这个是 \(\dfrac{n!}{\prod \text{size}_u}\),然后 \(\text{size}_u>1\) 的一定是一堆链底的标号,将链 reverse 一下就可以将这些点挂在链顶上,然后发现事实上就是维护所有原树的 \(\text{size}\) 即可,如果所有链顶构成的集合为 \(S\),那么就相当于只用维护 \(\prod \text{size}_{S_i}\)。直接使用树链剖分来维护所有的实链链顶即可,时间复杂度 \(\mathcal O(n\log n)\)。
ZR3062
考虑将题意转化为随机选取一个 \(n\) 的排列 \(p\),每个点在 \(p_i\) 时刻被选取,同时有一个 \(1\sim n\) 的辅助数组,每次选取出 \(x\),如果 \(x\) 未被标记,就让 \(kx\) 全部被标记,并让 \(ans\to ans+1\),最后统计的是 \(E(ans)\)。考虑拆贡献到每个位置上,如果一个点由自己标记,那么必然是其因子中最靠前的,概率是 \(1/d(x)\),那么 \(E(ans)=\sum_{x=1}^n\frac{1}{d(x)}\)。直接使用 \(\text{min25}\) 筛计算,时间复杂度 \(\mathcal O(\sqrt n)\)。
QOJ7513
萌熊题。考虑确定下来子序列含有的颜色集合后,只需要判定这些位置能不能连在一起形成一条链上的回文序列。注意到出现 \(1\) 次的颜色几乎是没用的,考虑把所有 \(2\) 次出现的颜色拿出来,相当于形成了若干路径,要求最大化集合 \(S\),使得 \(S\) 中的路径是两两存在包含关系的。现在仅考虑偶回文的情况,奇回文可以最终在中间判是否连续。
然后注意到你确定了最内层的之后就和外面的无关了,所以你需要求出一个 \(f_i\) 表示 \(S_i\) 作为最内层时能选多少条路径使得其是两两包含的。对于所有颜色的路径,按照 \(dis(u,v)\) 倒序排序去考虑一定是没有后效性的。转移就是询问包含路径 \((u,v)\) 的路径 \((x,y)\) 的最大值,容易用 dfs 序来刻画到一个二维平面上。需要动态加点以及矩形 \(\max\),可以树套树维护,时间复杂度 \(\mathcal O(n\log^2n)\)。
QOJ8229
Subtask 2 是直接树状数组上二分,Subtask 3 是维护 \((\max,+)\) 矩阵。
操作序列是重要的,并且还是区间修改单点查询,因此考虑离线掉询问然后扫描线序列维,数据结构维护时间维。那么就可以差分掉弹栈以及压栈的操作为 \(l\) 处加入 \(r+1\) 处删除的单点修改,询问就是考虑其时间。询问注意到 \(p,q\) 是没有太大用的,可以改成 \([1,q]\) 减去 \([1,p-1]\) 的和。并且考虑将一个操作序列结束后的状态刻画为一堆在最前面的 pop 操作以及后面的有效 push 操作。
分块的根号 \(\log\) 做法就不说了,大概就是维护整块的向前操作效果,查询时从后往前暴力找所有块,对于后方的 pop 直接二分其在这一块的加入序列中的位置。
考虑使用线段树维护,当前的栈需要用两个信息来描述:栈中所有数的数量以及栈中所有数的和。对于一个时间轴而言,我们关心的是在 \(r\) 的时刻结束之后,后侧会传来多少次 \(\text{pop}\) 操作。后侧的信息会影响前侧,记录这条信息才可以进行信息合并,因此考虑使用楼房重建线段树,合并信息时进行单边递归。每个节点的信息是:对于时刻 \([l,r]\) 维护如果仅执行 \([l,r]\) 的操作,其在 \(r\) 时刻结束后栈中的和以及个数,另外需要维护向前的剩余弹栈操作的数量。维护就考虑设计一个函数 \(\text{query}(l,r,x)\) 表示对于时间轴 \([l,r]\),后方传来 \(x\) 次 \(\text{pop}\) 操作,最终的整体效果。单侧递归即可。最终时间复杂度 \(\mathcal O((n+m)\log^2m)\)。
神秘模拟赛 T2
题意:给定值域为 \([1,n]\) 长为 \(n\) 的序列 \(f\),求有多少值域 \([1,n]\) 的序列 \(g\) 使得任意 \(f_{g_i}=g_{f_i}\)。\(n\leq 5000\)。
不难发现对于弱联通块而言,关心的是图论关系,并且这些连通块是相互独立的。考虑用图论的语言来描述,对于 \(f\) 可以建图,对于所有 \(i\in[1,n]\) 连有向边 \(i\to f_i\),这样就形成了内向基环森林,记为 \(T\)。首先考虑特殊性质的做法,\(f\) 互不相同,即形成的图是若干环的做法。注意到一旦确定下来某个 \(g_i\) 的取值之后,对应环中所有 \(g\) 的取值都是确定的,枚举环上随便一个点 \(g\) 的取值,然后顺着推一遍看是否正确就行了。考虑树的做法。注意到对于一个环上的根 \(x\) 而言可能会有多个 \(f_i=x\),那么就有 \(f_{g_i}=g_x\),如果 \(g_x\) 确定了这些 \(g_i\) 也是确定的,就可以自上而下地推下去所以设 \(f_{u,i}\) 表示子树 \(g_u=i\),\(u\) 中子树所有点 \(v\) 填写 \(g_v\) 的方案数,转移枚举每个儿子填哪个数就好了。之后由于弱连通块独立,枚举环上的随便一个点的 \(g\),跑一遍得到每个点的真实值,如果合法然后就对答案加上 \(\prod f_{u,g_u}\) 即可。时间复杂度 \(\mathcal O(n^2)\)。
noi.ac 3643
考虑先写一个 \(\text{dp}\) 完成一个序列 \(b\) 的判定,那么就是 \(f_{i,j}\) 表示前 \(i\) 个数中 \(j\) 结尾的 \(k\) 间距子序列的最大长度,转移就是继承 \(f_{i-1,j}\) 并且令 \(f_{i,a_i}\) 是 \(f_{i-1,j}+1,j\in[a_i-k,a_i+k]\) 中取 \(\max\)。存储这个 \(i\) 明显是不必要的,可以直接维护,线段树可以直接维护出对于给定的 \(a\) 当前的所有 \(f\)。问题即为往后接尽量多的数,使得最终的 \(f\) 依然符合所有数 \(\leq l\)。往后面加数时事实上只需要考察对于 \(f\) 的变化。那么贪心的策略就是,如果 \(f'_i\) 表示当前结尾添加 \(i\) 后这个取值的最长 \(k\) 间距子序列,即 \(f_i'=\max_{j\in[i-k,i+k]} f_j+1\),那么策略一定是选取 \(f'_i\) 最小的位置进行修改。因为每次是 \(+1\),所以操作最小值的位置不会影响非最小值的位置。也就是说先操作一定不劣。现在的问题是如何快速模拟这个过程。我们考虑扫值域,每次从提升 \(f'\) 的最小值由 \(p\to p+1\) 来考虑。如果当前 \(f'\) 的最小值已经超过 \(l\) 就寄了,否则考虑所有能变化的点即最小值的所有位置的集合 \(S\),因为你初始扫完前缀 \(a\) 得到的有值的 \(f\) 是很少的,所以很多点可以放在一起考虑,那么 \(S\) 就可以被刻画成若干极长连续区间 \([l_i,r_i]\),而一个点会影响周围 \(2k+1\) 个 \(f'\),所以任意 \(r_i-l_{i-1}>2k\),那么操作就相当于是独立的,提升一次时一个区间大概就是 \(\lceil\frac{r_i-l_i+1}{k+1}\rceil\) 的时间使得 \(f'\) 全部上升,然后由于关键 \(f'\) 值的值域是小的,所以可以拿 std::set
维护所有区间进行快速维护,合并以及拆区间时的代价都是容易计算的。瓶颈在于线段树以及区间的维护,时间复杂度 \(\mathcal O(n\log n)\)。
noi.ac 3644
在判定两个线段相交的时候,不考虑 \(h_0\) 时只需要考虑其在环上相对位置,然后将连边看成一个区间,理由是判定其代表的劣弧是否相交,再判定其是否是不包含但是相交的关系。然后考虑最终连边的形式,就是至少一个连向 \(h_0\) 的点使得环上不允许跨越这条线段,然后就断成了形如一堆弧不允许碰边界,这显然是一堆互不影响的子问题,断环为链后直接就是若干区间 \([l,r]\) 内部连边使得其内部包含的点连通的结果,然后 \(l,r\) 是通过 \(h_0\) 连通的。然后再注意到权值函数的性质,\(h_0\) 相连的边不会大于 \(2\) 条,原因是这样至少存在两个与 \(h_0\) 大小关系相同的点与之相连,这样可以给这两个点相连,然后再选一个点连向 \(h_0\),是更优秀的。问题的瓶颈还是来到了那个锤子区间 dp。
考虑对于区间 \([l,r]\),意思是环上意义的区间 \([l,r]\),即出现 \(l>r\) 时就代表 \([l,n]\cup[1,r]\),\(l=r\) 就代表与中心点相连不允许跨过。这样就把所有弧都刻画出来了,记这个最小值是 \(f_{l,r}\)。转移即枚举或向中间的某个点连边即可。为了处理中间点额外设计一个dp。考虑连完其他边后,中心点在的中间的多边形的边,每条边背后都是一个 \(f_{l,r}\)。相邻两个边可以直接首尾相接形成一个连通块,这样中间点只需要向这个连通块连一个边;也可以相邻两个边中间空出一个位置裂成两个连通块。枚举一个分裂点,dp 一下即可做到 \(\mathcal O(n^3)\)。
然后考虑 \(h_0\) 变化的情况。由之前只能与两个点相连的结论,我们可以将 \(h_0\) 按照所有 \(\mathcal O(n)\) 个 \(h\) 进行分段,然后考虑中心点的连边方式来进行统计答案。如果中心点连了一条边,可以分讨其是较大值还是较小值。对于每种情况,均可以写成:如果 \(h_0<x\) 答案就和 \(h_0+y\) 取 \(\min\)。预处理,然后最后二分寻找一下即可。
最终时间复杂度 \(\mathcal O(n^3+q\log n)\)。
AT_agc028_e
字典序问题考虑贪心填前缀,问题就是考虑一个前缀确定后后缀是否存在满足要求的方案。一个前缀的有效信息是:序列 \(A\) 当前前缀最大值的个数 \(c_0\) 以及最后一个前缀最大值 \(x_0\),序列 \(B\) 的前缀最大值个数 \(c_1\) 以及最后一个前缀最大值 \(x_1\)。这两点信息是有效的。你的判定就是后缀两边的差是平衡的。一个显然的性质是,原序列的前缀最大值一定是新序列上的前缀最大值。令两个序列新增的前缀最大值位置集合分别为 \(a,b\)。
如果从 \(|a|-|b|\) 的角度上进一步分析,那么有一个锤子结论是,考虑 \(p[i+1:n]\) 中所有前缀最大值的位置集合 \(S\),直接给出结论:\(a,b\) 其中必有一个只由 \(S\) 中的元素构成。必要性是显然的,充分性就是考虑反证。它的等价表述是 \(a,b\) 均存在位置 \(i,j\) 使得它不属于 \(S\)。那么我们分别找出最前面的 \(i\) 以及最前面的 \(j\),那么 \(i\) 前面比它大的那个 \(S_k\) 就必定属于 \(B\),\(j\) 前面那个比它大的 \(S_l\) 就必定属于 \(A\)。一个合法的关系就是 \(k,i,l,j\) 分别形成了 \(2143\) 的关系。那么交换 \(i,j\) 所在集合就会导致 \(i,j\) 均不会成为各自的前缀最大值,而 \(S_k,S_l\) 依旧,此时 \(|a|-|b|\) 是不变的,因为两者都减小了 \(1\),我们只需要满足 \(|a|-|b|\) 不变就好了。
接下来进一步考虑,不妨设 \(a\subseteq S\),就设 \(b\) 中不属于集合 \(S\) 的有 \(x\) 个,属于集合 \(S\) 的有 \(y\) 个。那么要求就是 \(c_0+|S|=x+2y\)。我们可以直接对右边的式子进行 \(\text{dp}\),令 \(S\) 中的元素权值为 \(2\),其余的权值为 \(1\),我们需要求的是一段后缀的一个首项 \(>x_0\) 的一个上升子序列,我们关心的是它的权值是否可以达到 \(x+2y\)。可以发现通过去除开头的 \(1\) 个或者 \(2\) 个最小值得到同奇偶的其他答案。那么我们只需要对权值分开维护,记录奇偶分开的最大值。直接 \(\text{dp}\) 用支持单点修改区间询问最大值的线段树维护即可。总时间复杂度 \(\mathcal O(n\log n)\)。
PR #8C / T529361
首先考虑对于每个 \(i\) 的暴力怎么做,扫描线序列,然后对于所有的限制区间维护一个堆,每次加入这些区间。考虑给 \(a_i\) 分配的是当前未分配完的区间中 \(r\) 最小的,然后弹出这些堆顶直到限制区间或者 \(a_i\) 没有了。注意到这个差不多是一个二分图匹配的模型,左边你可以对于每个人拆成 \(a_i\) 个小点,右边对于每个区间拆成 \(b_i\) 个小点。我们考虑计算 \(p=i\) 位置的答案,那么我们相当于先进行 \(p\) 位置右侧的匹配,并使得剩下的区间 \(l\) 尽可能小。考虑右侧前 \(i\) 个人用不完的流量 \(s_i=\sum_{l_j\leq p\leq i\leq r_j}b_i-\sum_{j=p}^i a_j\)。那么根据 Hall 定理,\(\max_{p\leq i\leq n}s_i\) 的流量就会剩到左侧去参与匹配。
令严格最大值代表值最大中下标最小的。找到 \(s\) 序列中严格最大值的位置 \(k\),那么找到 \(p\leq r_j\leq k\) 中 \(l_j\) 最小的区间 \(j\)。,那么 \(\min(b_j,s_k − \max_{p\leq t\leq r_j}s_t)\) 就是区间 \(j\) 最多可以浪费的。我们将这部分流量按照端点 \(l_j\) 加到左部分,再对 \(s\) 数组进 行后缀减的操作。不断进行这个过程,我们就可以维护出左部的剩余流量,对左部维护线段树即可求出最大匹配。
势能分析我不会,大概就是令势能为线段树中,当前子区间 $[l,r] $中严格最大值在 \([\text{mid}+1,r]\) 的个数, 操作一次则会使势能至少减少 \(1\)。更新次数是 \(\mathcal O(n\log n)\) 次的,每次操作需要线段树,总时间复杂度是 \(\mathcal O(n\log^2n)\)。
20241101
UOJ895
特殊性质 \(\text{A}\) 是合法解有且仅有 \(2\) 组(奇数层外向,偶数层内向);特殊性质 \(\text{B}\) 是 \(2-\text{SAT}\) 问题的字典序最小解。
考虑确定一个前缀的定向之后判定之后是否存在合法方案。现在删去已经合法的路径(即路径上存在反向边)之后,限制是所有路径中,已经确定的边的方向均与路径方向相同的路径,那么就形如当前一条路径的子集 \(S\subseteq E\) 中(\(S\) 是没有确定放方向的边的集合)至少存在一条反向边。如果 \(|S|=0\) 就是显然无解的,因为这条路径无法被调整并且已经寄了,否则考虑 \(|S|=1\) 的是可以直接对 \(S\) 中唯一的元素进行定向的,不断缩直到不存在 \(|S|=1\) 或者宣告方案是不合法或者合法的。考虑在不存在 \(|S|=1\) 时,由特殊性质 \(\text{A}\) 进行二染色必然有解,我们断言一个结论:如果当前未确定合法的路径中,其中未定向的边集合 \(S\) 均满足 \(|S|>1\) 时,这种情况是一定有解的,因为这个限制是弱于性质 \(\text{A}\) 的。直接暴力做的复杂度是 \(\mathcal O(nm^2)\) 的,结合性质 \(\text{AB}\) 期望获得 \(48\) 分。现在瓶颈在于快速缩掉所有 \(|S|=1\) 的路径。可以考虑在确定边的方向同时去缩掉 \(|S|=1\) 的路径,使用堆以及队列等数据结构优化寻找的过程可以做到 \(\mathcal O(nm\log m)\),期望获得 \(64\) 分。
再之后呢?打开洛谷题解区,发现青白老师写的很好/bx。
进一步优化的方向就是维护这个 \(|S|=1\) 的队列。瓶颈在于如何找到 \(|S|=1\)。考虑一个报警器的 trick,可以将一个路径拆到若干链上,然后数据结构维护这些链,当链上未被定向的边数达到 \(0,1\) 时分别报警一次。然后寻找的复杂度就是拆成 \(k\) 条链,我们希望在 \(\mathcal O(\text{poly}(k))\) 的复杂度内找到。对于这个拆链,点分治,倍增,树剖都是可行的。树剖做法需要拆成 \(\mathcal O(\log n)\) 段轻重链剖分上的区间,每个还需要在线段树上 \(\mathcal O(\log n)\) 定位,这样的复杂度是 \(\mathcal O((n+m)\log^2n)\)。对于倍增做法,考虑拆成 \(u\) 到其 \(2^i\) 级祖先的路径,那么朴素做法中需要暴力维护的,对于每条边,每条覆盖其的路径,可以优化到直接往这些倍增路径去连边。然后对于每个限制拆成 \(\mathcal O(1)\) 条 \(u\to\text{lca},\text{lca}\to v\) 的直链。对于每条倍增区间,需要维护它的信息:确定的边中,不存在被确定的,均为内向,均为外向,方向混合;同时记录未确定方向的边的个数,如果是恰好 \(=1\) 的就需要记录它的编号。容易发现,单次确定某条边的方向之后就可以 \(\mathcal O(\log n)\) 更新,然后做一遍类似拓扑排序的东西来维护报警过程即可。然后对于一个倍增区间,向合并它的两个部分连边边数就是正确的 \(\mathcal O((n+m)\log n)\),这样就可以直接用 \(O(\log n)\) 的复杂度处理,而每个倍增区间只会被更新 \(\mathcal O(1)\) 次。最终总时间复杂度 \(\mathcal O((n+m)\log n)\)。另种思路同样是倍增,但是考虑树上带权并查集维护缩边过程。常数很大,LOJ 和 UOJ 分别只能获得 \(88\) 分以及 \(84\) 分。
P10610
一个明显的结论是,如果 \((u,fa)\) 这条边被操作了,那么 \(w_u\) 就最终确定了。注意到一个点的点权是 \(w_u,w_u+c_{fa_u},w_u+w_{fa_u}\) 三者之一,分别对应 \((u,fa)\) 不操作,\((u,fa)\) 在 \((fa,fa_{fa_u})\) 之后操作,\((u,fa)\) 比 \((fa,fa_{fa_u})\) 先操作或者后者不操作,这几条边是几乎独立的,所以有了具体的 \(\text{dfs}\) 序之后再构造答案是容易的。所以可以去考虑先构造 \(\text{dfs}\) 序,再构造具体的操作方案。这东西可以考虑用一个 \(\text{dp}\) 来做,就是维护一个 \(f_{u,i}\) 表示 \(\text{dfs}\) 序的第 \(i\) 个为 \(u\) 是否可行。由第一个分析而言,如果 \(c_i\notin\lbrace w_u,w_u+c_{fa_u},w_u+w_{fa_u}\rbrace\) 就一定无解,那么搜的时候当然还需要记录一下 \(c_{fa}\) 的取值。而 \(\text{dfs}\) 序的美好性质是对于一个子树 \(u\),就恰好映射到 \(\text{dfs}\) 序的一个区间上 \([u,u+\text{size}(u)-1]\),我们要做的就是考虑对于儿子 \(v\) 是否存在符合要求的排列。注意到树的形态是同一深度的节点儿子数目相等,那么对于同一深度的节点,每个子树的大小可以归纳得到是相等的。那么所有儿子 \(v_1,v_2,\cdots,v_k\) 的 \(\text{dfs}\) 序需要排列到的就是 \(i+1\) 开始公差为 \(\text{size}(v)\) 的等差数列 \(p_1=i+1,p_2=i+1+\text{size}(v),\cdots,p_k=i+1+(k-1)\text{size}(v)\),因为这棵树的性质,这些点对所有都是一样的。我们可以看成,需要寻找一个排列。直接看成二分图完美匹配,左部图代表每个儿子,右部图代表 \(p_1,p_2,\cdots,p_k\),如果 \(f_{v_i,p_j}=1\),那么我们直接连边 \((L_i,R_j)\),跑一遍匈牙利或者网络流即可求出完美匹配,如果不存在完美匹配必然是无解的。最后需要输出方案,因此还需要记录匹配的方案。
考虑确定了 \(\text{dfs}\) 序之后,将边抽象成一个点,那么考虑在一张顺序限制关系的图上,就有一堆边 \(u\to v\) 表示原图上的边 \(u\) 必须比原图上的边 \(v\) 的操作时间早。边变成无向之后是个森林,因此直接在这个 DAG 上跑一遍拓扑排序即可。因为需要二分图匹配,时间复杂度上界是 \(\mathcal O(n^2\sqrt n)\),明显跑不满。
AT_agc049_c
考虑没有修改怎么做。显然 \(a_i>b_i\) 时是可以不会影响 \(0\) 位置的机器人。对于 \(a_i\leq b_i\) 的肯定不能让它执行完这些操作,要么就是直接更改操作序列,要么就是让 \(a_i\) 被摧毁。考虑将这些执行视为区间 \([a_i-b_i,a_i]\),那么对于 \(a_i-b_i>0\) 的区间,我们可以任意顺序执行,那么就对于这些区间按照 \(a_i\) 升序去执行,那么就可以让这些区间的并集的 bot 报废,但是接下来(都是会抵达 \(0\) 的)如果存在 \(a_i\) 没有被摧毁就寄了。先对这些区间取个并集,然后考虑怎么消去所有当前不合法的 bot。第一种是直接让 \(b_i\) 减小到 \(a_i-1\),第二种是增加一个区间 \([a_i,a_i+1]\)。不难发现对于第一种操作我们最多执行一次,因为最后一个就可以直接把前面的存活 bot 全部带走。枚举最后一个使用第一种操作的 bot,扫一遍就好了。时间复杂度 \(\mathcal O(n\log n)\),瓶颈在排序与离散化。
AT_agc061_e
操作是没有交换律的,考虑让操作 \(1\) 往位运算去靠,对于某次 \(+1\) 就是将一个最低位的 \(1\) 连续段置为 \(0\) 然后在原来的结尾的前一位置的 \(0\) 更改成 \(1\)。这样做是不太会影响高位的,然后对于这个题划分阶段的过程就是前缀推平的过程,因此考虑在这个基础上,按低位来推到高位进行 \(\text{dp}\),进行了一次很长的前缀推平之后就可以声称对于低位是个新的状态了。我们可以倒推整个过程,那么最后一次前缀推平而言,前缀相当于全 \(0\),我们可以 \(\text{dp}\) 如何将这个全 \(0\) 变化到与 \(T\) 相等的低位。但是你还要考虑对于高位使用的这些 \(\text{xor}\) 操作的影响,那么 \(\text{dp}\) 状态就是:\(f_{i,0/1,msk}\) 分别表示考虑最低的 \(i\) 位,要求进行加法操作不会进位到严格高于 \(i\) 的所有位;初始这个状态是 \(S\) 的最低位还是全 \(0\);最终整个过程使用了 \(msk\) 集合中的 \(\text{xor}\) 操作(即在低位执行的过程中这些操作被执行了奇数次);要求最终与 \(T\) 的最低 \(i\) 位相同,求出最小代价。
考虑状态的转移,如果全程没有恰好推平到 \(i\),状态合法的充分必要条件就是要求 \(((typ\times S)\oplus Y_{msk})_i=T_i\),其中 \(x_i\) 表示二进制意义下 \(x\) 的第 \(i\) 位,可以直接通过 \(f_{i-1,typ,msk}\) 来进行转移。但是考虑如果全程恰好推平到了 \(i\),那么你前面位的状态是存在一个全 \(1\) 的,所以这样设计状态是明显不够用的。拓展状态,直接拓展终止状态是全 \(1\) 或者与 \(T\) 相同。然后 \(\text{dp}\) 就长成了一个很对偶的形式:\(f_{i,0/1,0/1,msk}\),最低 \(i\) 位要求不使用进位超过 \(i\) 的 \(1\) 操作,起始是 \(S\) 的最低 \(i\) 位还是全 \(0\),要求变到终止的样子是 \(T\) 的最低 \(i\) 位还是向前进位的状态,最终往高位传递的就是 \(msk\) 集合的 \(\text{xor}\) 操作。要求出最小代价。这样做的状态就是充足的。同样,如果第 \(i\) 位不干任何事情就可以匹配,直接进行朴素转移;否则考虑两次进位之间的调用相当于把一个全 \(0\) 变为全 \(1\)。考虑从 \(t_0\) 状态开始,变化到状态 \(t_1\),那么中间可能出现多次进位状态的变化,但是使用的 \(\text{xor}\) 集合可能是不同的,写成 \(\text{dp}\) 的路径就是 \(f_{i,t_1,1,a_1}+f_{i,1,1,a_2}+\cdots+f_{i,1,1,a_{k-1}}+f_{i,1,t_1,a_k}\to f_{i,t_1,t_2,\oplus a_i}\)。这相当于一个最短路的形式,用类似的 \(\text{dijkstra}\) 每次从 \(\text{dp}\) 的堆中取出最小的未被使用的,更新的复杂度是 \(\mathcal O(4^n)\),统计答案是平凡的,直接就是 \(\min\lbrace f_{\text{maxbit},0,0,*}\rbrace\)。考虑转移是最短路形式,需要用一个朴素的 \(\text{dijkstra}\) 算法做,需要用堆维护,因此最终复杂度 \(\mathcal O(4^n\log V)\)。
20241102
becoder D9T3
\(\text{CF888G}\) 但是期望。
考虑直接进行 \(\text{dp}\),那么答案就是 \(f_{n,m}\) 表示 \(n\) 个点,每个点点权在 \([0,2^m-1]\) 中随机的 \(\text{xor-mst}\) 的边权总和的和。进行拆位,令集合 \(S\) 中的数满足 \(a_i\) 的第 \(m\) 位为 \(1\),剩余集合 \(T\) 中的满足 \(a_i\) 的第 \(m\) 位为 \(0\)。那么一个关键的性质是 \(S,T\) 均非空时,\(S\) 与 \(T\) 的连边有多于一条边是肯定不优的,不然最高位的 \(2^m\) 的贡献一定劣于 \(S,T\) 中内部连,后者的上界是 \(2^m-1\)。那么 \(S\) 与 \(T\) 之间只需要连一条边,也就是连接 \(\min(S_i\oplus T_j)\) 即可,在原问题给定 \(a\) 之中直接在 \(\text{trie}\) 树上模拟一遍即可。然后求解 \(f_{n,m}\) 就有一个递推式:枚举 \(0\leq i\leq n\) 表示有恰好 \(i\) 个数的第 \(m\) 位为 \(1\),按照 \(n,m\) 分别升序求解,那么就容易由之前 \(f\) 的信息得到,但是还需要维护:\(g_{k,L,R}\) 表示分别有 \(L,R\) 个数,点权均在 \([0,2^k-1]\) 中随机,要求出所有 \(\min(L_i\oplus R_j)\) 的和,求解 \(f_{n,m}\) 就需要 \(g_{m-1,i,n-i}\)。
考虑求解 \(g\)。值域很小,你可以直接把所有 \(\min\) 全给钦定了。那么可以要求所有 \(L_i\oplus R_j\) 均 \(\ge k\),那么 \(=k\) 的数量就是 \(\ge k\) 的数量减去 \(\ge k+1\) 的数量,因此再设 \(h_{k,L,R,d}\) 表示分别有 \(L,R\) 个数,点权均在 \([0,2^k-1]\) 中随机中,\(\min(L_i\oplus R_j)\ge d\) 的方案数,有了 \(h\) 再做一遍容斥求出 \(g\) 是容易的。再考虑求解 \(h\)。考虑根据最高位是 \(0/1\) 然后将 \(L,R\) 分别划分成 \(L_0,L_1,R_0,R_1\),再递归地消掉这一位往低位走即可。
时间复杂度 \(\mathcal O(n^4m2^m)\)。
QOJ6807
对于环可以拆成链,考虑拆成两条不交链以及合并两链断点的边。使用随机染色的 trick,考虑对所有点随机黑白染色来处理不交的限制,则最大环恰好有一半连续的黑点,一半连续的白点的概率为 \(k2^{-k}\)。随机 \(T\) 次的错误率是 \((1-k2^{-k})^T\),\(T=1000\) 时就已经达到 \(10^{-5}\)。于是采用类似 CSP-S2022 T1 的做法,处理链长为 \(4\) 的情况即可。
UOJ738
串的最终形态一定是 \(\text{((((...))))}\),然后对输入的括号串 \(S\) 考虑建括号树分析,建立这棵树使得其长 \(2n\) 的括号序为 \(S\),一个节点 \(u\) 对应原序列一个合法括号序列子区间,记一个点的权值 \(a_u\) 就是这个括号序列的首个左括号对应的权值。那么两个操作就分别是:以 \(0\) 的代价交换两个相邻的子树,事实上可以直接改成任意排列所有儿子的顺序,所以对于一个节点,儿子的顺序是不重要的;对于两个相邻的儿子 \(v_1,v_2\),权值分别为 \(a_1,a_2\) 的话,就是将 \(v_2\) 的所有儿子以及节点 \(v_2\) 本身挂到 \(v_1\) 上,然后以 \(xa_1+ya_2\) 的代价执行本次操作。因为可以任意排列顺序,所以可以将相邻的限制去掉。最终目标就是将树变成一条链。从而,我们断言,存在一种最优解是将所有节点按照深度由浅到深的顺序进行修改,即操作 \(d\) 深度的节点时要求 \(1\sim d-1\) 深度的点各有一个,形成了一条链的结构。进而,我们甚至是不关心具体的树结构的,因为在操作 \(d\) 深度时他们的父亲就都是那个链的链底了,所以我们只关心 \(d\) 深度有哪些节点。
考虑测试点 \(9\sim 12\),即 \(x=0,y=1\),被合并时,前者不产生代价,而后者会产生代价并且把该节点向下传递。注意到一层只能保留一个节点,那么都要下传时,我们可以保留代价最大的节点作为链的第 \(d\) 个节点,直接维护一下当前深度的所有权值以及权值和即可快速维护出保留深度 \(d\) 的代价。可以用 \(\text{multiset}\) 维护,时间复杂度 \(\mathcal O(n\log n)\)。考虑 \(x=1,y=1\) 时,记备选第 \(d\) 层的节点集合是 \(S\),每次操作两个深度为 \(d\) 的节点两者都会产生代价,然后可以拆贡献到每个节点,有系数 \(k_u\),目标是最小化 \(\sum k_ia_i\),然后保留一个节点,感性理解最大值当前不被处理到后面处理的代价会更大。那么最优策略就一定是先合并到 \(v_{\min}\) 上,然后再由 \(v_{\min}\) 与 \(v_{\max}\) 合并,这样只有 \(v_{\min}\) 的系数 \(k\) 是 \(|S|-1\),同样可以用 \(\text{multiset}\) 维护,时间复杂度 \(\mathcal O(n\log n)\)。
考虑 \(x=1,y=0\) 的做法,那么本层保留 \(u\) 的代价就是 \(a_u+\min(S_i)(|S|-2)\)。此时贪心是没有正确性的,因为最小值下传下去可能造成的贡献会更小。考虑从系数 \((|S|-2)\) 入手,那么每层的系数记为 \(k_i=|S|\),\(|S|\) 在每一层都是固定的,所以最小值对应的系数也是固定的。每次会加入原始就在 \(d\) 深度的节点,然后存在新增节点的操作是一段前缀连续段,所以 \(k\) 的结构是:前面是单调不降,后面是公差为 \(-1\) 的等差数列。分析一下发现那个 \(a_u\) 事实上是没有用的,这个不与 \(S\) 具体是什么有关,\(\sum a_i\) 可以直接累加入答案,这样问题直接简化成最小化 \(\sum\min(S_i)(k_d-2)\),要求每次 \(|S|=k_d\),每次结束一层就踢出去一个元素。一个显然的贪心策略是在任意 \(k\ge 3\) 时直接保留 \(\min(S_i)\),每次踢出去的是次大值。但是你这样做的生效区间仅限于 \(k\ge 3\),由前面对于 \(k\) 序列的分析,这在 \(k\) 序列上大概会是一个 \([p,n-2]\) 的连续区间,在这段区间贪就是对的。最后两个 \(k=2\) 直接计入两者最小值,是平凡的,考虑找到这个 \(p\),即 \(k_1,k_2,\cdots,k_{p-1}\) 形成的结构是 \(1,1,\cdots,1,2,\cdots,2,2\)。直接枚举 \([1,p)\) 是哪个元素下传下来的,复杂度会是 \(\mathcal O(n^2\log n)\),但事实上下传下来的只会是前缀 \(\min\) 或者前缀 \(\max\),证明考虑交换不优,这样时间复杂度 \(\mathcal O(n\log n)\)。
20241105
ZR3042
这不是我们 NOI2024 D1T3 吗。
直接 \(\mathcal O(n^2)\) 的 dp 是没有救的。考虑对于一个点 \(u\),当前其入度可以在 \([l_u,r_u]\) 中取到,初始情况有 \(l_u=0,r_u=\text{deg}(u)\)。那么确定一条边时,其两个端点 \(u\to v\),就会出现 \(l_u\to l_u+1\),\(r_v\to r_v-1\)。考虑有解的一个必要条件是 \(W_{u,i},i\in[l_u,r_u]\) 中至少有一个 \(1\)。那么发现一个点如果满足:\(l_u\to l_u+1\) 之后依然有解就给染红,\(r_u\to r_u-1\) 之后依然有解就给染蓝。那么一个点是紫的话我们可以随便改,如果无色就是无解,如果是红色或蓝色就相当于边是被确定方向的。那么考虑不断执行这个过程,每确定一条边就判定其是否存在新的红色点或蓝色点,进而定向更多的未定向边,寻找更多的确定颜色的点。可以用一个队列维护这个迭代的过程。如果当前局面所有点都是紫色,那么其中一个未定向边定向后一定仍然有解,但仍然需要执行这个迭代的过程。时间复杂度 \(\mathcal O(n)\)。
ZR3044
先把所有点的邻域依次排开,那么就是需要给定一个长度为 \(2m\) 的序列 \(b\),需要维护一个长为 \(n\) 的数组 \(a\)。支持:区间 \(i\in[l,r]\),\(a_{b_i}\to a_{b_i}+v\);区间求 \(\sum a_{b_i}\)。考虑直接分块维护。那么需要将询问拆成以下四类:
- 修改的散块对查询的散块:暴力修改直接访问真实值即可。
- 修改的整块对查询的整块:处理一个整块 \(x\) 加上 \(v\) 对整块 \(y\) 的查询的贡献系数 \(\text{coef}_{x,y}\),询问进行一个二维前缀和状物。
- 修改的散块对查询的整块,修改的整块对查询的散块:同样考虑单点对整块的系数即可。
时间复杂度 \(\mathcal O((m+q)\sqrt m)\)。
ZR3074
考虑固定 \(k\) 怎么做。对于所有区间按照第一关键字 \(r\) 从小到大,第二关键字 \(l\) 从大到小进行排序。那么可以维护 \(k\) 个教室当前最后一个活动的右端点 \(R_i\) 构成的可重集 \(S\),每次贪心对于 \([l_i,r_i]\),找到 \(l_i\) 在 \(S\) 中最大的 \(R_j<l_i\),如果存在 \(R_j\) 就在 \(S\) 中将 \(R_j\) 删去并加入 \(R_i\)。使用 multiset
维护可以做到 \(\mathcal O(n^2\log n)\)。感性理解一下,\(k+1\) 的最优解一定由 \(k\) 继承,也就是每个区间有一个值 \(f_i\) 表示 \(k\ge f_i\) 时这个区间就一定被取。
接下来考虑求 \(f_i\),可以考虑二分,模拟一遍 \(<i\) 的区间的加入情况,判定 \([l_i,r_i]\) 是否可以插入,这样做的复杂度没有优化。考虑整体二分,也就是 \(\text{solve}(l,r,x,y)\) 表示已经确定 \(f_{i}\in[x,y],i\in[l,r]\),当前需要求出 \(f_{mid}\) 的值。考虑是否存在 \(k=t\) 的解的话,可以用一个判定:对于当前所有区间,统计每个单点被区间的覆盖次数,其最大值 \(\leq t\) 就是存在 \(k=t\) 的。这个是因为我们可以把两个相交的区间连一条边,这会构成一个区间图,而区间图是弦图,弦图的最小染色数等于最大团。因此直接在线段树上维护一下所有区间对于单点的覆盖次数即可,二分进入时要求已经插入 \([1,l)\) 的所有区间。合理地安排递归顺序即可。时间复杂度 \(\mathcal O(n\log n\log m)\)。
ZR3045 / AT_wtf22_day1_c
牛牛牛。
考虑对树黑白染色,那么每次删除的就是两个异色叶子。先考虑删干净之后是什么形态:一堆不交的子树会被删掉,剩下的是一个连通块。放到每个子树上分析,就是要对里面做一个完美匹配,但是如果要删干净可能会有异子树。维护一个 \(cW_u,cB_u\) 分别表示子树内黑点以及白点的个数。显然一个方案可能存在一个子树内不完全匹配,剩下的这些点就需要和子树外面的点去进行匹配。感性理解一下,一个子树内需要完全匹配就需要往外面去借 \(T_u\) 个点。那么显然对于每个 \(u\),\(T_u\) 是存在一个下界的。然后考虑可行的与外面匹配的点就是 \(T_u,T_u+2,T_u+4,\cdots,\text{size}(u)\),需要同奇偶性的。对于 \(T_u\),考虑先是子树内贪心匹配掉一些,那么剩下的叶子一定都是同色的,进一步,不妨设 \(cW_u>cB_u\),那么所有叶子都是白色的,要想进一步消就要去借黑色节点来消掉白色叶子。不断重复操作直到 \(cW=cB\),会由外面借来 \(cW_u-cB_u\) 个黑色节点。此时,我们还是子树内能匹配就删,当删不了时,这个子树剩下的是一条从根向下的链需要借外面的点,我们贪心地想要最小化这个链的长度。\(f_u\) 就是链的长度加上 \(cW_u- cB_u\)。
先不考虑树删干净的情况,考虑给未删除部分随便定一个根,那么删除的部分就可以刻画为若干不交子树 \(t_1\sim t_k\),考虑找一下必要条件:根节点颜色不全相同,\(\sum cW_u=\sum cB_u\),\(f_u+\text{size}_u\leq \sum \text{size}_i\)。这个是充分的,构造考虑找两个 \(cW>cB\),\(cB<cW\) 的做匹配,然后可以归纳满足条件 \(3\),可以发现消完之后就剩下了一堆链,可以去满足条件 \(1,2\)。 有了这三个条件,去求 \(f_u\) 也是容易的。
计数就考虑枚举 \(\sum \text{size}_i\),然后在树上二维背包 \(\text{dp}\),记录黑色节点和白色节点个数、根是否颜色相同。求答案时枚举删除的节点中深度最浅的 \(u\),那 \(u\) 的子树补也是被删除的,换根一下就好了。时间复杂度 \(\mathcal O(n^5)\),明显是跑不满的。
20241106
湖南省集 D3T1
考虑固定集合的地点 \(R\) 之后,如何快速求有 \(k\) 个人集合的代价,显然确定了 \(k\) 之后,就会让这个地点为根跑一遍 \(\text{bfs}\) 序,然后取其前 \(k\) 小即可。注意到代价是凸函数,然后收益 \(w\sqrt k\) 也是凸的。所以总收益也是凸的,因此大体思路就是二分这个凸包即可。考虑具体的实现细节,需要维护与其距离 \(\leq k\) 的所有点的个数以及这些点的 \(\sum \text{dis}(i,u)\)。可以直接在点分树上进行维护。时间复杂度 \(\mathcal O(n\log^2n)\)。
湖南省集 D3T2
考虑如何快速判断两个序列是否等价,考虑上一个与其数值相等的位置 \(lst_i\),如果下标对齐显然就是判两者的 \(lst\) 数列是否相同。但可以直接维护数列 \(d_i=i-lst_i\),维护两者的 \(d\) 是否相同。枚举 \(l\) 扫 \(r\) 可以做到 \(\mathcal O(n^2)\)。然后考虑先去把 sunzh 诋毁一下。注意到本质不同子串的一种求法是后缀排序减去 \(\sum \text{height}\)。但是注意到子串是被转化的,也就是一个 \(d\) 可能会出现在整体中是存在前驱的,但是在一个子串中是不存在的。然后你事实上可以沿用固定 \(l\) 的思想,对所有转化过后的后缀进行排序,实现一个比较两个转化后的后缀的字典序,以及后续统计答案,都需要维护一个函数 \(\text{lcp}(s_x,s_y)\)。如果使用哈希,需要维护哈希值然后进行二分做到 \(\mathcal O(\text{polylog}(n))\) 实现一次 \(\text{compare}\)。倒序扫描线然后用主席树维护哈希值,可以单点修改一个点后继的哈希值,然后做到 \(\mathcal O(\log n)\) 单点查询某个后缀版本的哈希值。这样的时间复杂度是 \(\mathcal O(n\log^3n)\),瓶颈在于对所有后缀进行排序。期望得分 \(80\sim 100\)。主席树的查询是不够优秀的,改成分块来进行根号平衡即可。对于每一块处理出前缀哈希值以及整块的哈希值,时间复杂度 \(\mathcal O(n\sqrt n+n\log^2n)\)。
P11103
一眼图匹配的样子,因此写成网络流的形式。考虑建图为 \(S\to i\) 流量为 \(a_i\),\(i\to [l_i+n,r_i+n]\),每条边流量为 \(+\infty\),\(i+n\to T\),流量为 \(c_i\)。那么固定下区间后,答案就是这张图的最大流。考虑使用 Hall 定理,我们希望右部图有带权完美匹配。令选取的容器(右部图)集合为 \(S\),让它的权值和是 \(x\),那么 \(N(S)\) 表示与其相邻的左部图物品集合,令它的权值和是 \(y\)。我们要求 \(x\leq y\),考虑一个完美匹配的形式,增加一个能被所有容器匹配的权值为 \(d\) 的物品,那么就需要 \(x\leq y+d\),那么 \(d=\max(x-y)\)。总和减去 \(d\) 就是最大权匹配。那么就需要最大化:\(\sum c_{S_i}+\sum a_i-\sum a_{N(S)_i}\),后者表示区间与 \(S\) 无交的物品。
考虑特殊性质 \(t_i=1\),\(x\in S\) 时 \(N(S)=U\),可以全选,这个是平凡的;否则选择的一定是一个前缀拼后缀。使用扫描线计算即可 \(\mathcal O(n\log n)\)。对于没有特殊性质的情况,维护一下前后缀中只考虑 \(t=0\) 的区间的最大权值和 \(pre_i,suf_i\)。最优的 \(S\) 的形态可能是一堆极长的子区间,但是只需要考虑 \(x\) 是否在 \(S\),如果在的话考虑其极长连续段 \([L,R]\),然后拼上断点加上两端的即可。对于 \([L,R]\) 进行序列分治,时间复杂度 \(\mathcal O(n\log^2 n)\)。如果直接扫描线可以做到单 \(\log\)。
联合省选 2024 D2T1
又看了一遍,做法忘光了,竟然自己会了。
字典序首位的最大化是最强的限制。当前在 \(u\) 的话,作为 Alice,我们可以剪掉一些右子树使得剩下可以到达的叶子节点中的最小值最大。看到这个限制可以直接二分表示是否可以做到 \(\ge x\)。但是需要对所有 \(x\) 求的话就爆了。考虑 \(\text{dp}\),对于每个子树 \(u\) 维护 \(f_{u,i}\) 表示仅考虑 \(u\) 子树内的开关,第一步要到达 \(u\) 子树内叶子节点 \(q\) 的第 \(i\) 小的最小代价,同时维护一个 \(T_{u,i}\) 表示这个具体是谁,对于子树合并使用归并排序可以做到 \(\mathcal O(2^nn)\)。后面我们考虑直接模拟 Bob 的行走,然后相当于确定了首位 \(v\),那么考虑 Alice 最大化剩下的部分。考虑 \(v\) 到根的路径提出来,从底到根挂着的子树就是要依次求解的。注意到 \(f\) 只能帮助我们判断是否在最坏情况是合法的,给出一个代价的下界,具体决策还是要自己在模拟过程中去做的。相当于 \(f\) 是一个虚的东西,但是你每次做操作是实际发生的。那么从这条到根路径向下走到挂着的子树时,我们要为后面预留一些代价。考虑这个子树内的首位为 \(t\),如果 \(t<v\) 且当前子树的根是 \(u'\),如果 \(u'\) 的身份是一个右子树即 \(u'\) 为奇数,就必须要开启 \(a_{\text{fa}(u')}\),不然就会与预想的先走 \(v\) 冲突。此时实际的代价限制是 \([t<v\wedge 2\not\mid u']a_{\text{fa}(u')}+f_{u',\text{rank}(t)}+B\leq f_{u,\text{rank}(v)}\),其中 \(B\) 表示走出这个子树 \(u\) 后至少要剩下多少代价。那么问题在于怎么求出 \(B\)。这个直接对于 \(f_{u,v}\) 考虑它是怎么来的,直接减去这个子树的贡献,那么向下递归时剩下的就是一个路径后缀的限制,显然是对的。时间复杂度 \(\mathcal O(2^nn)\)。
20241107
P5279
考虑建立一个自动机来描述正在胡牌的过程,目标就是考虑让每个节点表示一个状态,两个节点(状态)之间的有向边描述了一个状态的转移。因为最多出现 \(4\) 次,某种牌最多在胡牌的子集中贡献两次。内层做的时候考虑一个能描述限制较强的条件 \(1\) 的状态。条件 \(2\) 要求是有至少 \(7\) 种牌的出现次数 \(\ge 2\);条件 \(1\) 要求是存在对子且剩下至少有 \(4\) 个面子。直接可行转最优化,设计 \(\text{dp}\) 为 \(trans_{i,j,k,0/1}\) 表示考虑了 \(1\sim i\) 的牌,是否已经存在预留的对子,当前有 \(j\) 个 \((i-1,i)\),当前剩下的 \(i\) 有 \(k\) 个(准备让面子的开头是 \(i\)),最大的面子数量。另外记录一个 \(cnt\) 表示当前出现至少两次的颜色数量。注意到有效的 \(j,k\) 均在 \([0,2]\) 之中,因为根据麻将的思想,可以直接让 \(3\) 个大小相邻的面子拆成 \(3\) 个数值相等的面子。然后这个 \(\text{dp}\) 的状态是少的,直接写个 \(\text{bfs}\) 发现自动机大小只有 \(3619\),代码实现可以用 std::map
进行判重。
考虑期望怎么求,可以拆成,如果在 \(x\) 时刻没有胡牌就计入 \(1\) 的贡献,那么问题就是加入 \(x\) 张牌没有胡牌的方案数 \(g_x\)。求出 \(g\) 后统计答案是容易的。那么在自动机上 \(\text{dp}\) 就是计数 \(f_{i,j,k}\),考虑前 \(i\) 种颜色,有多少摸出来 \(k\) 张牌的方案使得当前在节点 \(j\)。转移是容易的。时间复杂度 \(\mathcal O(|\Sigma|n^2)\),其中 \(|\Sigma|=3619\) 表示自动机大小。
CF1987G2
显然 \(l,r\) 都可以一遍单调栈求出,并且事实上那张图不考虑值为 \(n\) 的节点,那么就是一个森林,然后原图要求连通那么只能让最大值连自环,其余的不连自己,所以事实上是一棵树。这个东西看上去很笛卡尔树,直接对原序列建出来大根笛卡尔树 \(T\),那么有一些不存在后继或者不存在前驱的节点的 \(s_i\) 必然是确定的,可以直接进行修改。判定这些点是容易的,如果与已有冲突就是无解。
然后考虑刻画连边:\(u\to l_u\) 就是 \(u\) 跳祖先,首次以右儿子身份往上跳;\(u\to r_u\) 同理。注意到形态就是往祖先连边的。那么我们考虑让新树直径端点为 \(x,y\),如果不是直径的话可以不管他,因为最后是取 \(\max\),也就是说统计的是 \(T'\) 上两点距离的最大值。然后考虑在 \(T'\) 上 \(\text{lca}(x,y)\) 处统计贡献,最优化主动想一下 \(\text{dp}\),发现在 \(T\) 上 \(\text{dp}\) 然后让最大化的东西是两条分开的链的 \(T'\) 的边数就是有救的。再观察一下 \(T'\) 边的形态,都是连到某一级祖先上,然后需要维护这个 \(T'\) 的链顶到当前 \(T\) 上的点的路径上,是否有左儿子上传的边,是否有右儿子上传的边。然后需要考虑一下这个子树上传两条链的情况。先看一下答案的形态吧,你最后要做的事就是考虑两条链分别来自两个子树,或者同一个子树上传两条点不交的链在此点相遇。因而你的 \(\text{dp}\) 是要带上 \((u,fa)\) 这条边的。
如果在上方相遇的,那么走出这个子树就要求两个中一个选 \(l\) 一个选 \(r\),不然就会产生冲突。所以 \(\text{dp}\) 状态就显然是维护,\(f_{u,0/1/2}\) 分别表示,当前要跳出 \(u\),链中已经存在左儿子上传边,或者右儿子上传边,或者两者都有,此时 \(T'\) 链长的最大值。那么对于 \(2\) 的话要求两个 \(x\to u,y\to u\) 在 \(T'\) 上链经历的点集 \(S_x,S_y\) 是无交的。注意 \(\text{dp}\) 的状态中前两种均是只上传一个链,第三种是两条链的情况。注意如果 \(u\) 是根节点就不是良定义的。
考虑转移。首先对于路径中点不包含 \(u\) 的情况,转移是 \(f_{u,0}=f_{ls,0},f_{u,1}=f_{rs,1},f_{u,2}=f_{ls,}+f_{rs,1}\)。再考虑路径中包含 \(u\) 的情况。如果 \(u\) 允许选择 \(l\),转移就是 \(f_{u,0}=\max(f_{ls,1},f_{rs,0})+1,f_{u,2}=\max(f_{rs,2},f_{ls,1}+f_{rs,1})+1\),第一个表示已经完成了一个子树传上来的新点的路径,第二个分别表示继承右子树,将一个选 \(l\) 的更新了;或者合并两子树去让右子树的路径跳过 \(u\)。对于允许 \(u\) 选择 \(r\) 的情况是对称的。统计答案与转移是类似的,就是统计 \(T'\) 上两端点的 \(\text{lca}\)。时间复杂度 \(\mathcal O(n)\)。
20241108
ZR3077
问题显然是求出给定若干 \(\text{dfs}\) 序的区间构成的点的导出子图中连通块数量 \(t\),最后输出 \(t-1\)。首先求出 \(\text{dfs}\) 序,并且将点重新标号成 \(\text{dfn}\),考虑 \(k=1\) 的做法,就是选取一堆完整的子树以及最后一个不完整子树。考虑这些完整子树,维护一个 \(nxt_u=u+\text{size}_u\) 表示跳出 \(u\) 子树之后的位置。那么对于 \(k=1\),可以从 \(l\) 开始不断跳直到 \(l>r\)。求出跳的次数可以用倍增做到 \(\mathcal O(\log n)\)。
对于 \(k>1\) 的情况,考虑先倍增求出每个区间内部的连通块个数,直接累加入答案,然后求一下跨区间连通块合并的情况,只有可能是一条边 \((u,v)\) 使得 \(u\in [l_i,r_i],v\in[l_j,r_j]\),不妨设 \(u<v\) 即 \(u\) 为 \(v\) 的父亲,那么 \(i<j\)(输入顺序是 \(r_i<l_{i+1}\))。离线可以做这个二维数点,但是本题强制在线捏。注意到 \(u\) 作为一个完整子树中的点是不可能的,那么 \(u\) 只能是 \(l_i\) 跳到的最后一个连通块中的某个点。并且对于 \(v\) 的性质就是一定是 \(l_j\) 开始跳 \(nxt\) 跳到的某个根上。树的性质满足从标号来看这是一个小根堆。考虑对于一个残缺子树其 \(\text{dfn}\) 是若干区间 \([u_i,r_i]\)。只有这些会对后续的产生贡献。考虑对于一个这样的区间 \([x_i,y_i]\) 如何计算当前这个 \([l,r]\) 的贡献。找一下树的标号性质,发现在向后跳 \(nxt\) 的过程中,这个 \(fa\) 的标号也是有单调性的。因此可以对于每个 \([x,y]\),跳到第一个 \(u\) 使得 \(fa_u\in[x,y]\),然后再倍增看一下有多少在里面就好了。然后对于 \([x,y]\) 并不需要暴力判,如果某一时刻没有贡献那么在后续也没有捏。使用栈来维护残缺子树区间,时间复杂度 \(\mathcal O((n+k)\log n)\)。
CF2030F
注意到对于 \([l,r]\) 合法就一定有 \([l,r-1]\) 以及 \([l+1,r]\) 如果存在就是合法的,那么可以对于每个 \(l\) 求出最大的 \(r\) 使得 \([l,r]\) 是合法的,可以使用双指针维护。那么问题在于实现 \(\mathcal O(n)\) 次判定一个区间 \([x,y]\) 是否合法。正难则反,考察在什么结构下是不存在合法解的。可以使用建图的思想,如果 \(x\) 必须在 \(y\) 之前被操作就连边 \(y\to x\),问是否存在合法拓扑序。那么考虑什么时候成环,不难发现对于一个环长 \(>2\) 的情况一定是存在一个二元子环的,那么就是出现一个长度为 \(4\) 的子序列 \(i_1<i_2<i_3<i_4\) 使得 \(a_{i_1}=a_{i_3}\ne a_{i_2}=a_{i_4}\),因为这样会形成一个二元环。那么重新考虑问题,令 \(nxt_i\) 表示 \(i\) 的下一个与之相同的位置,那么就要求不存在相交但不包含的两个线段 \([i,nxt_i],[j,nxt_j]\)。这一步在扫描线过程中就要求加入区间 \([j,nxt_j]\) 时对应的区间 \(\min\) 是正确的,线段树维护可以做到 \(\mathcal O(n\log n+q)\)。
QOJ9532
考虑处理平均值问题的经典方案是二分答案 \(mid\),那么就是给所有数减去 \(mid\) 之后判是否存在以 \(u\) 为根的连通块使得其和 \(\ge 0\)。此时有一个 dp 就是 \(f_u\) 表示包含 \(u\) 的连通块总和最大值,转移就是 \(f_u=w_u'+\sum \max(f_v,0)\)。这样做是 \(\mathcal O(n^2\log n)\) 的。考虑优化,类似一个整体二分的思路,我们希望对于一个 \(mid\) 让一堆信息放在一起进行维护,因为这个 dp 信息对于同一个 \(mid\) 是完全可以继承的。那么考虑倒序从大到小扫描线 \(mid\) 的值,此时每个点的权值 \(w_i'\) 是在不断增加的。我们希望找出所有有用的 \(\mathcal O(n)\) 个 \(mid\),使得某个 \(f_u\) 由 \(<0\) 变为 \(\ge 0\)。注意到一个点变为 \(f_u\ge 0\) 之后其父亲会必然选择这个 \(f_u\),直接加上即可。合并可以使用并查集,加 multiset
维护求出下一个关键时刻,即小于 \(0\) 需要加上 \(f_u/\text{size}_u\),时间复杂度 \(\mathcal O(n\log n+n\alpha(n))\)。
20241109
P10041
区间 dp 可以从操作顺序倒着入手。
萌熊搬了,这我哪会啊。题目给出的性质 \(p_i-p_{i-1}<w\) 的意思是一旦到达了 \(k\) 并且需要卖出一定是立刻卖出而不是先再向上提高再卖出。显然有一个 \(f_{l,r}\) 表示区间 \([l,r]\) 的答案,但是完全无法转移,因此要多设状态。区间 dp 的转移可以考虑最后的状态。考虑合并是怎么来的,那么一个史莱姆事实上就是若干同色史莱姆的合并体。对于一个区间,如果最后被消除成了一个,考虑最后一个合并的史莱姆怎么来的。如果不存在最后一次合并,也就是这个史莱姆不是合并而来,是个单点,那么代价就是确定的 \(p_k-(k-m_i)w\),此时 \([1,i-1],[i+1,n]\) 都是被消除干净的;如果存在最后一次合并,也就是这个史莱姆是因为消掉了一些子区间使得剩下的都相同然后再合并上来的,这个同色子序列需要满足在之前的合并过程中质量均 \(<k\),那么就需要划分成前后两部分使得质量和均 \(<k\),最后一次合并之后可能还需要提高到 \(k\)。对于所有 \(1\leq i<k\) 可以定义一下 \(p_i=p_k-(k-i)w\)。注意到此时这个子序列将整个区间分割成了若干子区间,因为这些子区间是互不干扰的,所以这个最后一次的代价就是这些子区间的 \(f\) 的和加上合并到最后一次操作所需要的代价。
考虑如何刻画这个同色子序列,当然可以沿用区间 dp 的思路,并且要求一个区间的端点是恰好被选的,那么区间的转移可以由,对于当前的右端点,新拼上一个区间的右端点,要求这两个同色。那么状态就是明晰的:考虑对于一个区间,\(R_{l,r,d}\) 表示子序列的质量和为 \(d\),区间 \([l,r]\) 中要求 \(r\) 被选入同色子序列,也就是子序列颜色均为 \(c_r\),此时被断成的子串的 \(f_{l_i',r_i}\) 和的最大值。同理可以设计一个 \(L_{l,r,d}\),但是是对于 \(c_l\) 的。状态数是 \(\mathcal O(n^2k)\) 的。分别对于 \(l,r\) 进行设计的原因是枚举两个子序列分别的开头结尾是十分浪费的,这样做是 \(\mathcal O(n^4k^2)\) 的。\(L,R\) 自身的转移是容易的。考虑统计 \(f\) 就是枚举颜色,并且这两个子序列相当于一个前缀的 \(R\) 一个后缀的 \(L\),这个可以对于所有 \(L\) 预处理找到最优的,这个是容易枚举两个状态进行统计的捏,瓶颈也就在于此。时间复杂度 \(\mathcal O(n^3k^2)\)。
P6630
考虑一个点存在标记的概率为 \(f_o\),如果被 pushdown
到标记就要求其祖先中存在标记并且寻找线段划分的路径过程中可以经过它的父亲,因此需要维护一个祖先中存在至少一个点有标记的概率 \(g_o\)。最终答案为 \(\sum f_o\),由于 \(k\) 很大,所以可以猜到这是一个矩阵快速幂的题。先在递归过程中考虑一下,考虑将节点区间 \([l,r]\) 与修改区间的关系分类:无交,\([l,r]\subseteq [ql,qr]\),剩余均是相交但不包含,但是还需要考虑父亲区间 \(I\) 与 \([ql,qr]\) 的关系,这是因为一个区间尽管无交,但是其父亲如果获得标记且继续往儿子 pushdown
的话当前区间也会获得标记。因此需要考虑父亲区间 \(I\) 与 \([ql,qr]\) 的关系。重新考虑是 \(I\subseteq [ql,qr]\) 时会令 \(g_o'=1\);\(I\) 与 \([ql,qr]\) 无交集 \(o\) 的信息就不变;\(I\) 与 \([ql,qr]\) 相交但不包含:此时如果 \([l,r]\subseteq [ql,qr]\) 那么 \(f_o'=1,g_o'=0\);如果 \([l,r]\) 无交但是 \(I\) 有交即不会递归到 \(o\),那么 \(f_o'=1-(1-f_o)(1-g_o)\) 表示减去自己和祖先上都没有标记的概率,\(g_o'=0\);如果 \([l,r]\) 仍未停止还会往下递归,那么 \(f_o'=g_o'=0\)。对于每个 \([ql,qr]\),其贡献系数都是随机到它的概率 \(1/{\binom{n+1}{2}}\),然后产生一个新的 \(f,g\)。这些都可以直接求和。注意到转移形式与 \(k\) 以及操作次数无关,那么可考虑矩阵快速幂优化。在一次转移中,新的 \(f,g\) 可以由原来的 \(f',g'\) 由一个线性系数求出,分别表示五种不同的转移各自发生的概率 \(p_1,p_2,p_3,p_4,p_5\),给定 \([l,r]\) 以及 \(I\) 时都是可以求的。时间复杂度 \(\mathcal O(nT^3\log k)\),其中 \(T=4\) 表示矩阵的大小。合并一下位置可以做到 \(T=3\)。
20241110
ZR2957
套路化的进行离线,放在右端点上进行考虑,然后考虑对于右端点 \(r\) 进行扫描线,然后对于一个当前子区间 \([x,r]\) 而言当前的和就是 \(pre_r-pre_{mn}\),其中 \(mn\in[x-1,r]\)。对于 \(pre_r\) 是会向后产生贡献的,考虑对于 \(pre_{mn}\) 就相当于是取一个后缀 \(\min\)。对于这个后缀 \(\min\) 是容易单调栈维护的,每次加入就在线段树上进行修改。考虑难点在于 \(pre_r\) 的历史最大值的维护。那么线段树节点需要维护的关键信息,不仅是当前的历史最值,还有所有历史版本中当前位置历史最值的和,维护一个辅助数组 \(b\) 表示历史最值减去这个位置当前值。在单调栈更新时,对于 \(b<0\) 就需要重置成 \(0\),可以用 \(\text{segbeats}\) 维护。时间复杂度 \(\mathcal O(n\log n)\)。
20241111
ZR3058
首先回退到第 \(k\) 次操作可以使用操作树进行离线。考虑令 \(v\) 恒定为 \(1\) 单位每时刻,那么每次减速就是让剩余的 \(s\) 变成 \(2s\)。每单位时刻让 \(s\to s-1\)。考虑先离散化一遍所有一操作的 \(t\)。然后一个点代表一个关键区间,形如进入时 \(s=x\),出去时令 \(x=2(x-len)\)。那么每个函数就形如一个线性变换,最终 \(x=0\) 就代表停下了。线段树维护就需要对一个区间 \([l,r]\) 维护:该区间内有多少个减速 \(c\),如果想在通过这个区间时 \(x\ge0\)(可以恰好停在 \(r\) 位置上),\(x\) 在进入 \(l\) 时刻时至少为 \(x'\),且 \(x'\) 通过这段区间的线性变换后变成了 \(y\),这样的三元组 \((c,x',y)\) 是需要维护的,此外还需要维护一个线段的线性变换 \(y=kx+b\),合并是容易的。由于每次是单点修改,所以这个是可以接受的。如果超过取模范围,需要有特殊的标记。时间复杂度 \(\mathcal O(n\log n)\)。
ZR3086
唐诗评测机。考虑 \(k=0\) 的做法,图是一棵内向基环树,因此可以处理出每个连通块的信息。对于一个连通块,考虑其在 \(+\infty\) 时间后每个点一定都在环上,找出他们走到的位置,对于此进行等价类的划分。\(k=0\) 的答案就是所有等价类大小的最大值。考虑 \(k>0\) 的做法,枚举最终在哪个连通块进行聚合。如果花费 \(1\) 次操作将这个连通块的环改成自环,可以将剩下 \(k-1\) 个大小最大的连通块接过来,这种情况是平凡的,直接排序后求出所有的前 \(k\) 大连通块大小之和。但是如果不是自环,我们可以将 \(k\) 个大小最大的连通块接过来。对于本连通块可以计入一个该连通块内部等价类大小的最大值,考虑别的连通块,就需要枚举断掉哪条环边,然后考虑让这内部的树上深度模 \(y\),其中 \(y\) 为当前统计的连通块的环长,来划分等价类。注意到 \(y\) 只有 \(\mathcal O(\sqrt n)\),目标就是线性统计每个连通块(基环树)的模 \(y\) 等价类数量最大值。枚举每棵基环树被修改的环边,此时删除不同的环边会有不同的影响,更改的代价是挂着的子树大小,做一个类似于换根 dp 的东西即可。时间复杂度 \(\mathcal O(n\sqrt n)\)。需要注意优化一下寻址。
QOJ9615
一个显然的性质是如果有 \([l,k]\) 合法且 \([k+1,r]\) 合法就有 \([l,r]\) 合法,还有一个必要条件是所有数的和是 \(2\) 的倍数。先考虑判断一个数列是否合法:那么先形式化地刻画一下操作方式:找 \(a_i>1\) 让 \(a_i\to a_i-2\);找 \(1\leq i<n\) 且 \(a_i,a_{i+1}>0,a_i=a_{i+1}\) 让 \(a_i\to a_i-1,a_{i+1}\to a_{i+1}-1\),问最后能否变成全 \(0\)。这个和奇偶性是强相关的。考虑操作 2 改变奇偶性但是操作 1 不改变奇偶性。那么我们希望执行操作 2 直到所有 \(a\) 都变成 \(2\) 的倍数,只要所有 \(a_i\ge 0\) 就是合法的。考虑目标是奇偶性全部相同且 \(\min(a_i)\) 最大化时这个值 \(\ge0\)。我们的操作可以对着全部相等这个方向,如果相邻两数奇偶相同,可以操作成 \(\min(a_i,a_{i+1})\);如果 \(a_x,a_y\) 中间有偶数个相等的数 \(v\) 且 \(v> \max(a_x,a_y)\),那么显然可以将 \(a_x,a_y\) 合并到这个连续段里,新的大连续段值为 \(\min(a_x,a_y)\)。考虑扫描线这个序列,先考虑所有 \(a\) 足够大的情况。做一个类似于括号匹配的东西。那么可以不断消去奇偶性相同的相邻下标,消消乐一下看能不能消除干净或者消除到只剩下一个。直接维护一个奇偶性的栈,必须从奇数开始,每次看是插入还是弹出,栈为空时认为栈顶是偶数。如果最终栈只剩下一个偶数或者为空就是合法的。考虑 \(a\) 任意的情况,那么一个点往前面匹配的情况,手玩一下发现要直接减掉操作前栈的大小。因此数值上的限制就是任意 $a\ge $ 操作前栈的大小捏,这样就可以 \(\mathcal O(n^2)\) 做第一问了。然后考虑对右端点进行 dp,栈的形态是确定的。\(f_{i,k,0/1}\) 表示前 \(i\) 个数构成的栈中,有多少个左端点其扫描到 \(i\) 形成的栈满足其是长度为 \(k\),结尾为奇数还是偶数的方案数。转移是整体进行转移,用一个 std::deque
维护一下即可做到 \(\mathcal O(n)\)。
CF1887F
萌熊。太困难了。注意到一个性质,当 \(r_i\ne r_{i+1}\) 时 \(a_i\) 的下一个出现位置必然为 \(r_{i+1}\),并且 \(a_{r_i}\) 与任意 \(i\leq j\leq r_i-1\) 的 \(a_j\) 都不相同。令存在某个 \(j\) 使得 \(r_i=j\) 的点 \(j\) 称为关键点,其集合记为 \(S\)。考虑对着整体颜色数量 \(col\) 去构造,下界就是考虑 \((i,r_i]\) 中的关键点都是互不相同的,即 \(L=\max \sum_{j=i+1}^{r_i}[j\in S]\)。整体颜色数量的上界 \(R\) 为所有 \(r\ne n+1\) 的 \(\min(r_i-i+1)\) 时。那么我们断言 \(L\leq col\leq R\) 是可能有解的。考虑构造前驱序列 \(b\),那么相当于要求 \(b_i=0\) 的数量恰好有 \(col\) 个。序列上从左到右扫描线 \(i\),连边 \(i\to b_i\)。考虑对于 \(i\) 找最靠左的没有被后面连边的点连过去,\(0\) 可以被连 \(col\) 次。正确性在于考虑跨过 \(i\) 的边的个数是 \([i,r_i]\) 内颜色数量 \(col\),可以证明在 \(col=L\) 时任意,\([1,i]\) 需要向左连的数量总小于等于需要向右连的数量,Hall 定理可证。时间复杂度 \(\mathcal O(n)\)。
20241112
QOJ9611
考虑这个式子直接做是挂掉的捏。进行一些转化:令 \(\prod x_i=\sum_{\text{sequence }t,t_i\in[1,+\infty]}\sum[t_i\leq x_i]\)。这样一个数列会在 \(t_i\leq x_i\) 产生 \(1\) 的贡献,合计贡献就是 \(\prod x_i\)。问题转化为,对于所有长度为 \(n\) 的 \(x_i\in[1,n]\) 的序列,计数有多少 \(m\) 行 \(n\) 列的矩阵,每行是一个 \(n\) 的排列且有 \(q\) 个位置给定,求所有 \(p_{j,i}\ge x_i\) 的方案数的和。考虑给定 \(x\) 且 \(q=0\) 怎么计算,每列的确定在哪个位置并不重要,不妨设 \(x_i\) 是从大到小排序的,那么直接从大到小填一下就可以了,大概就是一个乘积式。然后考虑不固定 \(x\),进行统一求和,设计一个 dp 表示 \(f_{i,j}\) 为有多少个 \(m\times j\) 的矩阵满足这些 \(x>i\),此时的所有方案数和记为 \(f_{i,j}\)。初始状态为 \(f_{n,0}=1\),状态合法当且仅当 \(n-i\ge j\),转移为 \(f_{i,j}\binom{k}{j}(\frac{(n-i-j+1)!}{(n-i-k+1)!})^m\to f_{i-1,k}\),意义为填最后的 \(k-j\) 列方案数以及选取前面 \(j\) 列的方案数之积。\(q=0\) 直接做是 \(\mathcal O(n^3\log m)\) 的。考虑 \(m\) 是很大的,但是 \(q\) 极小。令存在 \(q\) 个确定点的行列是关键的。因此可以去除掉这 \(q\) 个点之后对剩余的行列进行平凡 dp,但是 \(q\le 10\) 就考虑 \(2^q\) 的东西,给原先的 \(q=0\) 上加个状压。那么就是 \(f_{i,j,S}\) 表示有多少个 \(m\times (j+|S|)\) 的矩阵,满足 \(x>i\) 且考虑了 \(j\) 的平凡列以及 \(S\) 集合中的关键列的方案数。一个必须要考虑的系数就是 \(\binom{k}{j}\) 表示选取这些非关键列的方案数。那么就考虑一共有 \(c\) 个关键行,对于非关键行的系数显然就是 \((\frac{(n-i-j-|S|+1)!}{(n-i-k-|T|+1)!})^{m-c}\)。对于这 \(c\) 个关键行可以暴力考虑,预处理一个 \(g_{p,i,S}\) 表示对于第 \(p\) 个关键行有多少个定点不属于 \(S\),且这个值 \(\ge i\)。转移就是 \(\frac{(n-j-g_{p,S,i}-i+1)!}{(n-k-|T|-g_{p,T,i}-i+1)!}\)。注意到转移系数中的 \(S,T\) 之间没有联系,因此可以分别计算系数。枚举 \(k\) 后进行高维前缀和优化,时间复杂度 \(\mathcal O(n^32^qq)\),可以预处理快速幂消掉一个 \(\log m\)。
P11098
考虑移动的路径一定形成一棵树,那么每次就是询问 \((r_2,c_2)\) 以及 \((r_1,c_1)\) 在树上的 \(\text{lca}\)。那么考虑快速求出一个点的父亲。容易发现,对于同一行中,一个前缀的父亲是 \((r-1,c)\) ,剩下来的后缀的父亲是 \((r-1,c-1)\)。对于第 \(p\) 行,这个分界点可以用考虑在 \(a_i=p\) 之前的向前偏移的量,可以树状数组快速求出。考虑求 \(\text{lca}\) 的暴力方法是拽到深度相等后暴力一起跳父亲。考虑可以一起跳父亲来优化这个复杂度。对于同一层只有分界点 \(b_p\) 存在两个儿子,对于剩余的点都只有一个儿子。一种方法是重构整个树,另一种方法是首先离线掉询问,然后放到 \(r\) 上。那么我们从下往上进行合并,对于大部分询问我们可以直接继承,但是在分界点两个儿子处进行合并。使用线段树合并来维护这些往上跳的点,在合并过程中维护答案即可。具体而言,令线段树的下标为询问标号,对于一个后缀位移是大可不必的,用另外一个数据结构来维护一下真实标号到每个线段树根的映射即可,可以搭配链表进行维护。时间复杂度 \(\mathcal O((n+q)\log n)\)。
QOJ9607
最小值 \(k\) 可以取到每个点被覆盖次数的最大值,这个实际上是可以取到的。我们可以把两个相交的路径连一条边,这会构成 一个类似于区间图的东西,而区间图是弦图,弦图的最小染色数等于最大团。那么考虑构造怎么做,用一个增量构造的思想,我们希望让 \(k\) 的子问题递归到 \(k-1\)。考虑当前对于 \(k\),我们记录当前被路径覆盖次数恰好等于 \(k\) 的点集为 \(S\)。我们希望找出一些路径使得每条路径覆盖 \(S\) 中的点,且每个 \(S\) 中的点恰好只被一个选中的路径覆盖。然后对这些路径进行覆盖,染色之后删去这条路径并对其沿途的点的覆盖次数都 \(-1\)。这是容易树剖加线段树维护的。找出所有 \(S\) 中的点可以在线段树上进行二分。问题在于如何寻找这些路径。然后你发现其实任意顺序消都是对的,只需要找到任意一个路径然后去消 \(S\) 的点即可。找的过程就是抽出来一个 \(S\) 的点 \(u\) 然后找一下哪个路径经过了它,这个就是在 \(\mathcal O(1)\) 个矩形中找点(令路径两个端点的 dfs 序放到平面上),然后消 \(S\) 的过程也可以用一个树剖线段树维护。仔细思考一下那个矩形找点是完全不必要的,完全可以直接找到 \(S\) 中 dfs 序最小的点,然后消除以它为 \(\text{lca}\) 的路径。时间复杂度 \(\mathcal O(n\log^2n)\)。另一种做法是考虑将路径丢到 \(\text{lca}\) 上面进行消除,进行线段树合并的逆过程,时间复杂度 \(\mathcal O(n\log n)\)。
QOJ9631
这不是我们统一省选 2022 D1T2 吗。秒了秒了。考虑进行 \(01\) 的转化,对于所有 \(x\) 我们将 \(\ge x\) 的视为 \(1\),将 \(<x\) 的视为 \(0\)。那么对于一个事实上中位数为 \(k\) 的让它统计 \(k\) 次就好了。问题就是对于所有 \(x\in[1,\max(r_i)]\) 计算有多少序列的中位数 \(\ge x\),所有 \(x\) 的方案数 \(f(x)\) 求和就是答案。然后将考虑用 \(l_i,r_i+1\) 对所有数进行分段。相对大小关系是基本不变的,那么进行分段时我们考虑其方案数 \(f(x)\) 是一个 \(n\) 次多项式。然后只需要做 \(\mathcal O(n)\) 次 \(f(x)\) 就可以插值出来所有的 \(f(x)\) 点值,做个前缀和就好了,因为总共有 \(\mathcal O(n)\) 段,所以 \(f\) 需要做 \(\mathcal O(n^2)\) 次。考虑 \(f(x)\) 怎么计算,注意到如果存在三个数中至少有两个 \(1\) 就一定是合法的,因为每次都可以选长度为 \(3\) 的区间进行感染,可以对一个前缀进行 dp,状态就是 \(f_{i,0/1,0/1,0/1}\) 表示考虑了前 \(i\) 个数,是否存在合法的长度为 \(3\) 的区间,第 \(i-1\) 个是 \(0/1\),第 \(i\) 个是 \(0/1\) 的方案数。时间复杂度 \(\mathcal O(n^3)\)。
ZR3057
显然 \(h\) 和 \(x\) 都没有任何用,可以直接二分找一下 \([l_i,r_i]\) 表示 \(i\) 可以呼叫援军的范围。一个观察是如果从左边删除了这个点的话右边的信息是没用的,并且如果在一次删除中从左边删去了 \(i\),那么在更小的一个子区间中也能这样删去它,这个是不劣的。因此 \(i\) 不可以被删去的区间是 \(l\in[a_i,i]\) 或者 \(r\in[i,b_i]\)。那么求出 \(a_i,b_i\) 后就是简单的离线二维数点,容斥一下就是扫描线加树状数组容易维护的。对于攻击方向的限制就相当于强制钦定 \(a_i=0\) 或者 \(b_i=n+1\)。我们断言 \(a,b\) 均有单调性。求 \(a,b\) 是对称的,因此可以考虑整体二分,那么限制就是 \([l_i,i)\) 中均被删空才能去删掉 \(i\)。考虑使用如下的整体二分:维护区间 \([l,r]\) 以及编号的集合 \(S\)。我们已经确定了 \(S_i\in[l,r]\),现在需要判定 \(S\) 中的哪些元素 \(S_i\leq mid\),做完这一步后可以向下进行递归。扫描线 \(mid\to r\),维护无法被消去的点构成的栈。加入的时候判定是否可以从左删去即可。时间复杂度 \(\mathcal O(n\log n)\)。
20241113
ZR3089
注意到外层是最小化 \(\text{mex}\) 的和,因此可以直接定义 \(\text{mex}\) 是任意一个未出现的数。直接 dp 考虑 \(f_{u,i,j}\) 为 \(u\) 子树内,断开了最多 \(i\) 条边,\(u\) 所在的连通块的未出现的数是 \(j\) 时,剩余连通块和的最小值。这就是一个朴素的树上背包,时间复杂度 \(\mathcal O(n^2k)\)。由于树是随机的,那么 \(\sum \text{siz}_i\) 是 \(\mathcal O(n\log n)\) 的,考虑对于一个 \(u\) 有用的 \(j\) 只有子树内出现过的值,对于未出现的就有 \(f_{u,i,j}=0\)。因此在加入 \(u\) 的儿子 \(v\) 时,\(j\) 这一维只用遍历在 \(v\) 子树内出现过的权值。那么时间复杂度 \(\mathcal O(nk^2\log n)\)。可以进行 \(\text{dsu on tree}\) 或者线段树合并来脱离树随机的性质。
QOJ5357
考虑点分树的构造,那么考虑在原图中依次加入边,每次加入一条原图中的边 \((u,v)\) 就是合并两棵点分树。考虑如何合并两个点分树:把 \(u\) 到根和 \(v\) 到根的两条路径合并,而选取哪些点属于原来 \(u\) 的点分树的方案数可以用组合数预处理。直接树上 dp 维护 \(f_{u,i}\) 表示中原图以 \(u\) 为根的连通块,构成的点分树上 \(u\) 的深度为 \(i\) 的方案数,可以树上背包加前缀和优化,时间复杂度 \(\mathcal O(n^2)\)。
QOJ7646
可以将贪心思想拓展到操作某个点对全局的影响。
称呼原来的 \(b\) 数组是 \(lim_i\)。考虑先设一下每次用的量以及剩下的量。维护 \(s_i\) 表示前 \(i\) 个物品结束后剩下的优惠券个数,\(x_i\) 表示每个物品购买时使用的优惠券个数。那么就要求 \(x_i\leq\min(lim_i,s_{i-1}),s_i=s_{i-1}-x_i+\lfloor\frac{a_i-x_i}{c}\rfloor\)。可以直接拆成对一个前缀求和。目标就是最大化 \(\sum x_i\)。其实目标是减少被消耗掉的优惠券,我们称一个优惠券是有用的当且仅当最后它被直接贡献到了 \(\sum x\) 之中。最终剩下的 \(s_n\) 是被彻底浪费的。可以考虑每个点对后续的影响,可以将 \(d\) 可以一个个拆开来。对于前 \([0,a_i\bmod c]\) 的 \(x_i\) 而言,后缀的 \(s\) 都不变,\(d\) 是不变的;接下来 \(x\) 每增加 \(c\) 就会让 \(d\) 减少 \(1\);最后一步减的是 \([0,c-1]\) 是让 \(d\) 同样减少 \(1\) 的。考虑数组 \(b\) 表示 \(s_{i-1}-x_i\),那么就要求 \(b_i\ge 0\)。对于第一种操作就有对于后缀的 \(b_{i\sim n}\) 减一,\(x\) 加一;对于第二种操作就有对于 \(b_i\) 减 \(1\),对于 \(b_{i+1\sim n}\) 减 \(c+1\),令 \(x_i\) 加 \(c\);对于第三种操作,令 \(x\) 加上 \(k\in[0,c-1]\) 时,对于 \(b_i\) 减 \(k\),对于 \(b_{i+1\sim n}\) 减 \(k+1\)。一个策略是 \(b\) 决定了 \(x\) 的上限,因此操作 \(1\) 比操作 \(2\) 优秀,操作 \(2\) 比操作 \(3\) 优秀。那么一个明显的策略就是先把操作 \(1,2\) 做了,初始的所有 \(s_i=b_i=m\),可以从右往左先进行贪心,那么就可以处理出数组 \(p_i\) 表示 \(i\) 位置已经用掉的操作数量。需要考虑一下维护后缀 \(\min\) 之类的状物,这一部分是容易的。考虑操作 \(3\) 的部分,我们希望先做 \(c-1\),再做 \(c-2\),这样性价比是依次递减的。直接枚举看放了这个之后后缀是否有解,倒序扫一下也可以判是否能放当前 \(x=val\),复杂度 \(\mathcal O(nc)\)。那么考虑找这些位置的过程用数据结构优化一下。注意到 \(lim-x\) 是没有单调性的,然后你确定了一个 \(x\) 就是对一个后缀的 \(s\) 进行区间减操作。考虑维护当前的 \(x'\) 的上限 \(q_i\)。贪心完全可以取 \(q\) 最大的位置进行修改,直接对当前的 \(lim-x\) 进行排序,然后对于 \(s\) 后缀 \(\min\) 状物是显然单调的,直接用一个堆维护当前的 \(lim-x\) 的 \(i\),直接取出最大的判断是否满足 \(q\),如果满足就进行修改。使用线段树维护 \(s\),时间复杂度 \(\mathcal O(n\log n)\)。
QOJ7649
\(m\) 显然是没啥用的,只和大小关系有关,直接猜测答案是个关于 \(m\) 的 \(\mathcal O(n)\) 次多项式,然后进行拉插就可以得出 \(m\) 的答案。注意到从前往后确定就不可避免的需要记录所有存在 \(a_j>a_i\) 的 \(a_i\),可以整体进行计数。考虑按照所有严格前缀最大值进行分段的话,每一段内部是一个子问题的形式,然后考虑跨越的形式,你发现如果 \(a_k\) 落在最后一段的话,\(a_j\) 取到最后一个前缀最大值 \(q\),\(a_i\) 取到它前一个的前缀最大值 \(p\) 一定是不劣的。也就是说对于三个相邻的严格前缀最大值 \(p,q,r\) 而言,就要求 \(\forall i\in(q,r),a_i\ge a_p\)。然后最后一段内部就是值域区间确定的,枚举个长度也是确定的,这样就形成了 \((q,r)\) 内部的子问题和 \([1,q)\) 如何放置两个完全独立的子问题,就相当于一个一个前缀最大值的段去掉。这样 dp 就是好的,你注意到最终的 \(m\) 是和本质不同的 \(a\) 数量有关的,直接考虑有 \(k\) 个不同值即可。dp 的转移就是枚举最后两个前缀最大值,设计状态就是 \(f_{n,k}\) 表示 \([1,k]\) 都出现了且长度为 \(n\) 的合法方案数。这样求 \(m\) 甚至不需要用插值,时间复杂度 \(\mathcal O(n^4+qn)\)。
ARC114F
显然确定完划分方式之后重排就是将所有子段按照字典序倒序填。那么 \(a_1\leq k\) 是平凡的,直接让划分点是 \(1,2,\cdots,k\) 然后输出即可。然后注意到 \(a\) 互不相同的话就只关心首位的大小。注意到 \(a'\) 的字典序一定 \(\ge\) \(a\) 的字典序。那么考察一下 \(a'\) 与 \(a\) 的 lcp,发现我们一定是最大化它,因为调整的话一定是在第一个不同的位变大了。因此首先考虑二分 \(mid\) 判定保留 \(mid\) 的前缀是否可行。考虑前缀中的划分点以及后缀中的划分点,对于前缀中的划分点一定是一个 \(1\) 开头的下降子序列,不然就会被调整。考虑后缀中的每一个划分点都必然比 \([1,mid]\) 中的划分点要小,后手对这些划分点是要进行排序的。先考虑枚举 \(x\) 表示 \([1,mid]\) 中的划分点个数,一个串是越划分越劣的,后缀也要找尽量少的划分点。我们首先会想最大化一下前缀中最后一个划分点的最大值,对于一个前缀维护一个 set
,记 \(f_i\) 表示 \(i\) 结尾的最长下降子序列,显然对于相同的 \(f_j=f_k\),我们只会保留 \(a\) 值更大的,插入时更新一下就好了。然后对于后缀而言,取小的划分点一定是好的,随便维护一下就好了。算上二分以及 \(\text{check}\) 的时间复杂度,总共是 \(\mathcal O(n\log^2n)\)。
20241114
ZR3015
对于 \(n\leq 12\) 的部分分可以考虑进行状压 dp,\(f_{S,i}\) 表示对于 \(S\) 点集的导出子图用了 \(i\) 种不同的颜色来染,转移直接枚举 \(T\subseteq S,S_1\in T\),并预处理一个集合染同一种颜色的系数进行转移即可做到 \(\mathcal O((2^n+3^n)(n+m))\)。对于树的部分可以一个个剥掉叶子,给答案乘上 \(((k-1)\text{diff}_i+\text{same}_i)\)。观察到 \(n=89\) 时 \(m=98\),而 \(m-n=9\) 是很小的。考虑进行广义串并联图的操作,每次进行:删一度点,缩二度点,叠合重边的操作。对于删一度点可以直接给答案乘上 \((\text{same}_i+(k-1)\text{diff}_i)\),这就类似于树的剪叶子。对于叠合重边只需要将 \(\text{diff,same}\) 两者分别相乘。对于缩二度点而言需要给中间的点赋上具体的颜色,记 \(u\) 相接的是 \(p,q\),那么可以缩成一条 \((p,q)\) 的边,满足其 \(\text{same}=(k-1)\text{diff}_1\text{diff}_2,\text{diff}=\text{diff}_1\text{same}_2+\text{diff}_2\text{same}_1+\max(k-2,0)\text{diff}_1\text{diff}_2\)。然后缩完之后满足图上任意点度数均 \(\ge 3\),规模满足 \(3n\leq 2m,m-n\leq 9\),解出 \(n_{\max}=18\),然后再跑暴力状压即可。由于数据是随的,不需要太担心多测超时的问题。时间复杂度 \(\mathcal O(m\log m+6^{m-n}(m-n))\)。
CF2026F
又是一个神秘背包题哦。考虑对于 \(1\) 操作建图,对于一个新的店记录其父亲为 \(1\) 操作中输入的 \(x\)。显然是要离线的,然后事实上你可以直接看成一个操作树。然后一个父亲的操作会影响所有子树内的版本。考虑当前的物品序列长什么样。就是继承父亲的物品序列,发现是一个类似于 deque
的东西,要求支持物品的 push_back
以及物品的 pop_front
。要求维护当前的 \(01\) 背包的形态。问题是 \((\max,+)\) 背包不支持删除,但是可以考虑回退。直接线段树分治即可,时间复杂度 \(\mathcal O(q\log q\max p)\)。另一种是考虑在 dfs 过程中进行答案的计算。开两个栈来维护,如果栈空进行重构即可,然后 \(\mathcal O(p)\) 来合并。
CF2025G
这种匹配的 trick 可以放到一起考虑然后钦定前面的造成贡献。
考虑确定局面时的做法。设当前有 \(x\) 个人,\(y\) 个盾。那么对于 \(x,y\) 分别从大到小排序之后分别按序对应一定是最优的,exchange argument 或者感受一下都是对的。考虑那个实数是不好的,我们希望计算的是每个血完整的扣 \(1\) 所需的时间,就是剩余的人以及剩余的盾的总数量。记录所有关键时刻是存在人或盾消失的时刻。记录人的血量为 \(a_i\),他手上的盾的耐久为 \(b_i\),答案就是 \(\sum a_i+\min(a_i,b_i)\)。其中 \(a,b\) 均是从大到小排序的,现在就需要用数据结构来维护这个式子。动态插入是困难的,不妨设 \(a,b\) 互不相同,可以离散化实现。然后用二分图匹配来维护这个过程。那么可以将 \(a,b\) 都拉出来从小到大排序一下。将 \(a\) 视为 \(1\),\(b\) 视为 \(-1\),就需要对于每个 \(a\) 去找一个 \(b\) 来匹配。显然就是第 \(i\) 个 \(a\) 匹配第 \(i\) 个 \(b\),但是谁在后面就会造成贡献。如果一个位置是 \(a\),造成贡献当且仅当这个位置的前缀和 \(\ge 0\)。如果一个位置是 \(b\),造成贡献当且仅当这个位置的前缀和 \(<0\)。因此可以直接维护这个前缀和数组,支持维护:值分别为正负的位置的和;以及区间加正负 \(1\)。分块维护即可,时间复杂度 \(\mathcal O(q\sqrt q)\)。
QOJ7839
这叫题吗。
不难注意到,\(19901991^2\) 对 \(20242024\) 取模的答案是 \(1\)。所以我们只关心 \(z_{\gcd(i,u)}\) 与 \(w_i\) 的奇偶性。那么操作就是在 \([l,r]\) 构成的虚树上对 \(w\) 进行 \(\text{xor 1}\)。所以只需要查询有多少个 \(i\) 使得 \(z_{\text{gcd}(i,u)}w_i\) 为奇数。注意到 \(n\) 很小并且还是 \(0/1\) 的,考虑直接上 bitset
。可以维护 \(\lbrace z_{\gcd(1,u)},z_{\gcd(2,u)},\cdots,z_{\gcd(n,u)}\rbrace\) 的 bitset
以及整体 \(w\) 的 bitset
。分别记为 \(W\) 和 \(Z\)。有了 \(W,Z\) 之后可以直接按位与并且求 \(\text{popcount}\)。考虑求 \(Z\),我们发现 \(\gcd\) 状物可以做一些优化。注意到 \(u\) 的质因子是少的,因此爆搜 \(\text{gcd}\) 的值即 \(u\) 的所有因子。每次给 \(u\) 乘上一个质数 \(p\) 时考虑其变化即 \(p^k\to p^{k+1}\) 就会让 \(p^{k+1}\mid x\) 的 \(\gcd(x,u)\) 乘上 \(p\)。直接暴力维护,变化量的总和是 \(T=43474197\),可以接受。然后考虑维护 \(W\)。我们希望提取出 \([l,r]\) 的虚树范围的所有点。可以用以下方式维护:维护区间 \([l,r]\) 所有点的 \(\text{lca}\) 为 \(t\),那么这个虚树就是所有点到根路径的并去除掉 \(t\) 到根路径的并。这种神秘操作考虑使用分块来维护。那么求 \(t\) 可以用 \(\text{st}\) 表维护区间 \(\text{lca}\)。问题在于如何求出所有点的并 \(S\)。考虑进行分块。对于 \(l,r\) 在同一个块的情况,由于数据随机,所以只有 \(\frac{B}{n}\) 的概率,对于在同一块中可以进行 \(\mathcal O(n)\) 的暴力求出点集;考虑对于跨越一个整块的情况,我们可以借助其整块来求。整块并不好,我们只需要撒关键点,然后就相当于一段前缀一段后缀的并。对于一个关键点,前缀后缀的链并均可以暴力加。加到一个访问过的就不再跳,每个点最多被加入一次。因此时间复杂度是 \(\mathcal O(n\sqrt q+\frac{nq}{\omega}+T)\)。
CF2029G
首先生成原始序列 \(a\)。考虑大力 dp 一下,不难发现一个连续段可以缩到一起进行操作,也就是说 \(a\) 缩掉并且把 \(c\) 叠加一下。注意到实际原序列 \(a\) 是由操作生成的,因此这个序列的颜色段数量 \(\leq 2V\)。因为如果存在 \(>V\) 的可以直接看成一个 \(V+1\) 的,没有任何用。暴力 dp 就是枚举 \(v\) 并且记录前 \(i\) 个数,有 \(j\) 个经过 \(i\) 的前缀加,有 \(k\) 个经过 \(i\) 的后缀加,此时前 \(i\) 个数中等于 \(v\) 的所有数的最大的 \(\sum c\)。对于 \(j\) 我们是要不断消掉的,对于 \(k\) 是会不断增加的。枚举 \(b_i\ge a_i+k\) 表示真实值。由于是一个取 \(\max\) 的过程,并且当且仅当 \(j+k+a_i=v\) 会贡献到答案上,而最终统计任意的 \(f_{n,*,*}\) 均可以取到答案上,我们可以只考虑 \(j+k+a_i=v\) 时对转移时来的 \(j',k'\) 进行调整,否则你在后面进行调整是不劣的。也就是说,在 \(f_i\) 直接继承所有 \(f_{i-1}\) 的基础上考虑对所有 \(x\ge j,y\leq k\) 的 \(f_{i-1,x,y}\) 取 \(\max\) 后加上 \(c_i\) 对 \(f_{i,j,k}\) 进行更新。形如一个右下角的矩形 \(\max\) 以及单点修改,直接做可以是 \(\mathcal O(V^3\log^2V)\) 的。那么考虑对于每个 \(v\) 都去计算然后重新计算所有的 \((j,k)\) 其实是不可接受的。考虑设计一个能融合所有 \(v\) 的状态。我们可以选择 \(k\) 的维度进行降维化处理。移项一下,可以得到 \(j+a_i=v-k\)。如果我们将 \(v-k\) 固定了就是简单的。因此设计一个 \(f_{i,x,y}\) 表示前 \(i\) 个位置有 \(x\) 次前缀加,如果想让 \(i\) 合法就还需要在 \(i\) 执行 \(y\) 次后缀加,也就是说 \(v-k=y\),前面 \(i\) 个所有的最大 \(\sum c\)。这样转移就是从 \(f_{i-1,\leq x,\leq y}\) 取 \(\max\) 进行转移。最终 \(v\) 的答案就是 \(f_{n,\leq v,\leq v}\)。直接二维树状数组可以 \(\mathcal O(V^2\log^2V)\)。考虑进一步优化,每次我们要更新的是直线 \(y=x+a_i\),对于这些点对我们可以从左下扫描到右上,每次增加一下新的需要考虑的点,只需要分别维护行列的前缀 \(\max\)。使用树状数组维护,时间复杂度 \(\mathcal O(V^2\log V)\)。
ARC076F
考虑二分图最大匹配可以使用 Hall 定理的推论。如果对于左部图 \(L\) 存在最大匹配,那么最大匹配数等于 \(\min_{S\subseteq L}\lbrace|L|-\max(0,|S|-|N(S)|)\rbrace\)。那么我们只需要最大化 \(|S|-|N(S)|\) 即可。注意到 \(N(S)\) 是点集的并,然后你考虑就是一段前缀的并加上一段后缀的并。你考虑既然都给成了 \((l_i,r_i)\) 不可行的形式,你直接对于不可行区间求交集就好了。那么就是:选取一个区间的集合,最大化点数加上交集长度。按照 \(l_i\) 进行排序之后,钦定交集左端点是当前区间的左端点,考虑对一个交集的右端点判定是否可行,线段树维护即可。时间复杂度 \(\mathcal O(n\log n)\)。
20241115
CF2029H
(无向图)状压计数题中,容斥是常见的思想,联合省选 2024 就出过。
题目中给的特殊性质就是对于 \(S\),拓展到 \(S\subseteq T,S\ne T\) 的期望步数一定存在,这提示我们将贡献拆到集合上。考虑集合拓展的操作序列:时刻 \(1\sim t_1\) 的极大黑点是 \(S_1=\lbrace1\rbrace\),时刻 \(t_1+1\sim t_2\) 的极大黑点集合是 \(S_1\subseteq S_2,S_1\ne S_2\),以此类推,直到时刻 \(t_k+1\sim t_{k+1}\) 的极大黑点集合是 \(S_k\ne U\),在时刻 \(t_{k+1}\) 变为全集 \(S_{k+1}=U\)。其实有效的操作序列要满足 \(S\) 是互不相同的,定义一个操作序列的权值是期望步数,概率就是每步概率的乘积,只需要对此进行求和。由期望的线性性,我们可以将贡献拆到每一个集合 \(S\) 上。我们发现对于同一个时刻变化的区间内概率都是相同的,因此可以维护:在操作时有且仅有 \(S\) 集合被染成黑点的概率 \(f_S\),考虑当前为集合 \(S\),期望还需要多少步才可以拓展 \(S\) 到更多的节点上。答案即为 \(\sum f_Sg_S\)。显然 \(g_S\) 是容易 \(\mathcal O(2^nn^2)\) 求出的,由题目的特殊性质这个期望步数是一定存在的,答案也就是 \(\frac{1}{1-p}\)。对于 \(f\) 有显然的 \(\mathcal O(3^n)\) 做法,不可接受,并且系数都与 \(S\setminus T,T\) 都相关,信息量本身就难以接受。
瓶颈在于“恰好”拓展到 \(T\) 是很烦的。
山重水复疑无路。无法优化的话,考虑进行容斥。具体来说,维护一个 \(h_S\) 表示至多只有 \(S\) 中的点被染黑,也就是说 \(h_S=\sum_{T\subseteq S} f_{T}\)。考虑 \(f_S\to h_{S\cup T},|S\cap T|=0\) 的转移。转移只需要保证不会拓展到 \(S\cup T\) 以外的点就好了,并且需要减去 \(S\) 向外不拓展的概率。而两个集合之间的连边可以写成全集除以两个集合内部连边的乘积。转移系数就是两部分的概率乘积。维护 \(P(S)\) 表示点集 \(S\) 之中的边断开概率之乘积。系数容易拆到之和 \(U,S,T,S\cup T\) 有关。转移的形式就是 \(\text{val}(S)\text{val}(T)\text{val}(S\cup T)\to h_{S\cup T}\)。按照 \(|S|\) 从小到大做半在线子集卷积即可。具体就是用 FMT 来做变换,做点积后逆变换回去。时间复杂度 \(\mathcal O(2^nn^2)\)。
CF2035G2
这个二分的过程是假的,因为原数列是不存在单调性的,但是分治结构以及判定的点是完全确定的。因此你可以建立出来线段树表示分治结构。那么下落到 \(x\) 的路径是确定的,我们也可以确定路径上经过的点与 \(k\) 的大小关系,向左走满足 \(a_{mid}\ge k\),反之有 \(a_{mid}<k\)。先考虑第一问做法。对于一个保留的限制集合,我们考虑是否存在一个 \(a\) 可以满足所有限制,那么就是每个 \(a_{1\sim n-1}\) 就都有一个取值区间,如果某个区间为空就挂了。注意到一个点管辖的就是一段区间,就要求 \([l,mid]\) 中的限制最大值,小于,\([mid+1,r]\) 中的限制最小值。然而事实上你可以直接将限制拓展到关于 \(mid\) 的前缀和后缀,只需要将父亲节点的限制拼起来就可以得到。因此判定有解的充分必要条件是保留的 \(k\) 如果按照 \(x\) 排序是单调递增的。那么第一问就是简单的,按照 \(x\) 排序后求最长上升子序列即可。
计数的一个思路就是对于 \(x\) 维护一下以它为结尾的最长长度,同时记录方案数。考虑如何从 \(f_i\) 转移到 \(f_{j}\),要求 \(x_i<x_j\)。那么考虑方案数就是维护所有被 \([1,i]\) 完全包含的节点的方案数,我们定义一个节点为一个区间,节点的方案数是其划分点的方案数。转移的系数就是 \((x_i,x_j)\) 的填数方案数。考虑暴力跳 \(i,j\) 的父亲表示需要特殊考虑的点,就是说取值必须在 \([lmx,rmn)\) 之中的点,剩余点是平凡的。因为树高是 \(\log n\) 的所以可以接受,转移就可以 \(\mathcal O(m^2\log n)\)。优化也显然,考虑枚举两者的 \(\text{lca}\)。由于是 \(\text{lca}\),那么对于 \(j<i\) 的话,\(i\) 一定是以右子树的身份跳上去,\(j\) 一定是以左子树的身份跳上去。我们可以预处理 \(\text{lca}\) 关于左子树以及具体的 \(j\) 的贡献 \(L_{u,i}\),以及右子树以及 \(i\) 的贡献 \(R_{u,i}\)。因为树高很小,所以信息量是可以接受的。对于 \(L\) 可以视作一个二维平面,横坐标是 \(x\),纵坐标是 \(\text{lis}\) 长度,可以树状数组优化转移。时间复杂度 \(\mathcal O(m\log^2n)\)。另一种做法就是考虑消去 \(k\) 的限制。按照 \(k\) 从大到小插入,动态维护这个线段树的信息,对于 \(\text{lca}\) 本身的方案数拆下贡献即可。
CF2030G2
考虑 \(f(S)\) 怎么求。显然就是钦定一个公共点之后求所有代价和的最小值。然后考虑这样的事情,\(w(l,r,p)\) 表示使得 \([l,r]\) 覆盖点 \(p\) 的最小操作次数,我们希望让 \(p\) 与 \(l,r\) 的大小关系无关。可以直接将 \(w\) 转化为 \(\frac{|p-r|+|p-l|-(r-l)}{2}\)。而后面那个是常量,我们只需要求出 \(p\) 到 \(l,r\) 构成的 \(2n\) 个点的距离和的最小值。直接排序后取到 \(l_i,r_i\) 的第 \(n\) 大即为最小值。直接对所有的 \(l,r\) 的排序后重新标号使得其互不相同,枚举中位数 \(x\),然后考虑在它左右各选取了多少线段,式子是烦人的。需要对 \(x\) 属于 \(l,r\) 进行讨论,并且需要考虑所有跨越 \(x\) 的区间,以及仅在 \(x\) 一侧的区间。时间复杂度 \(\mathcal O(n)\)。
ZR2955
考虑用如下方式描述,而不是用一个栈:选择一个长度 \(\ge 2\) 的区间 \([l,r]\),要求内部颜色全部相同,将 \([l,r]\) 消去,合并两端。问是否可以消空整个序列。我们可以让下标不进行移位,显然删去的区间是不相交仅包含的结构,考虑写成一个匹配的形式,\(del_i\) 表示某次删去的 \(r=i\) 时此时的 \(l\)。构造出 \(del\) 序列之后还原操作序列用一个栈扫是容易的。考虑用一个类似区间 dp 的东西,直接区间 dp 可以做到 \(\mathcal O(n^3)\)。对于当前递归区间 \([l,r]\) 考虑构造消除它的方案。显然同色连续段我们可以缩到一起去操作,记录一下 \(len_i\) 表示第 \(i\) 个极长连续段的长度。感受一下,断开连续段去操作一定是不优秀的。那么记其有 \(k\) 个同色连续段,那么考虑 \(r-l=1\) 且 \(k=1\) 是可以消除掉的,否则考虑其不被内层区间覆盖的点,一定是同色且加起来长度 \(\ge 2\) 的。那么删除操作形如,删除头尾的连续段,或者删除中间的连续段并合并两端的 \(len\)。三者都要求 \(len_i\ge 2\)。在 \(k\) 奇偶性正确的情况下,我们一定会尽量操作中间的段而不是去操作头尾的段。所以可以考虑对 \(k\) 的奇偶性分类讨论。
当 \(k\) 为奇数时,如果正中间的 \(len\ge 2\),我们可以删去中间后合并,不断消除中间的连续段,一定是有解的;否则考虑正中间连续段的 \(len=1\)。考虑前面部分的最后一个 \(len\ge 2\) 在 \(A\),后面部分的第一个 \(len \ge 2\) 在 \(B\)。显然如果只在一侧或者都没有的话答案就是 \(\text{No}\)。令 \(p=A-1+n-B,q=B-A-1\),分别表示两端的长度以及中间的长度。每次操作相当于 \(p,q\) 都减少 \(1\)。如果 \(p>q\) 两者就可以相遇,否则我们说明 \(p<q\) 时是无解的(\(p=q\) 时 \(k\) 不是奇数)。直接构造即可。当 \(k\) 是偶数时,如果最终局面是两个 \(len\ge 2\) 的就对了。考虑这两个位置来自于原串的一段前缀和一段后缀,拆成两个 \(k\) 奇数的子问题即可,判断合法是 \(\mathcal O(1)\) 的,构造模拟一下即可。时间复杂度 \(\mathcal O(n)\)。
ZR2956
我们称呼可以移动的点是关键点。首先考虑一个最终关键点的分配关于当前点的最小移动代价,对于 \(u,v\) 匹配的话就是找到最大的 \(dis_{\text{lca}(u,v)}\),那么就是自底向上做一个最大权完美匹配。考虑贡献拆到每条边上,记原来子树 \(u\) 中有 \(p_u\) 个关键点,后来子树 \(u\) 有 \(p_u'\) 个关键点,那么边 \((u,fa)\) 的经过次数就是 \(|p_u-p_u'|\),贡献也是确定的。那么在此考虑如何描述一个子树寻找 \(k\) 邻域内关键点的状态,定义找到最近的关键点为匹配。如果一个子树内的所有点都已经匹配上了,固然是好的。此时从 \(fa\) 来接 \(u\) 的话需要考虑 \(u\) 的匹配状态。对于子树全部匹配的情况,如果 \(u\) 匹配点在子树内,我们需要记录 \(u\) 到其匹配点的距离;以及如果子树内未全部匹配的状态,此时想要找匹配就需要从 \(u\) 子树中最深的一个未匹配的 \(v\) 来向上找关键点进行匹配。dp 状态也就呼之欲出了:\(f_{u,i,j}\) 表示在 \(u\) 的子树中,最终有 \(i\) 个关键点,此时 \(u\) 到子树中与其匹配的点距离为 \(j\) 的最小代价,方便起见,我们可以令 \(j\to k-j\) 表示剩余还能移动的距离;\(g_{u,i,j}\) 表示在 \(u\) 的子树中,最终有 \(i\) 个关键点,\(u\) 中子树最深的未匹配的点到 \(u\) 的距离为 \(j\) 的最小代价。转移考虑合并 \(u,v\) 的子树,第二维是一个对于 \(m\) 取 \(\min\) 的树上背包。转移的具体细节可以用前缀和优化,\(f\) 是不会影响合法性的,但是 \(g\) 可能影响合法性。关于第二维的复杂度分析,不妨令 \(\text{size}_a\leq \text{size}_b\)。两个都 \(\leq m\) 时将 \(\text{size}_b\) 丢到每个 \(a\) 里算贡献,每个点贡献和是不超过 \(2m\) 的;一个 \(\leq m\) 一个 \(>m\) 时考虑对 \(a\) 子树内的点算 \(m\) 的贡献。每个点最多只会作为 \(a\) 子树贡献 \(1\) 次;两个都 \(>m\) 时合并不超过 \(\frac{n}{m}\) 次,每次复杂度 \(\mathcal O(m^2)\),因此树上背包的复杂度是 \(\mathcal O(nm)\)。总时间复杂度 \(\mathcal O(nmk)\)。
20241116
ucup 全是 trash。
QOJ1431
对于单次计算,考虑将决斗的过程用满二叉树来刻画,那么就是一个非叶节点代表一次决斗。计算一下 \(f_{u,i}\) 表示 \(u\) 子树胜者能力值为 \(i\) 的概率,可以树上背包进行分析,复杂度是 \(\mathcal O(n^2)\)。考虑计算主角获胜的概率,那么就考虑在满二叉树上往上跳,那么就需要打败一个兄弟子树的胜者。容易发现此时对应的是一堆区间 \([l,r]\),计算获胜的概率。此时只会考虑 \(\log n\) 个区间,并且总共涉及的就是 \(n\) 个点。去重之后,不难发现总共需要计算 \(n\) 个区间,对于这些区间做一下树上 dp。时间复杂度 \(\mathcal O(n^2)\)。询问的时候递归一下即可。
QOJ3575
考虑差分数组 \(d_i=a_i-a_{i-1}\),那么就是操作相邻相同的 \(d_i\) 然后合并成 \(d\) 的两倍,不存在相邻相同时即终止过程。考虑 \(d\) 放在二进制意义,那么就是合并相邻并且进行向左移位 \(1\) 的操作。显然正负不同无法合并,因此可以对相同的正负的极长连续段划分到一起解决。考虑按照 \(d/\text{lowbit}(d)\) 进行分段,我们称两个数有希望合并到一起就是当且仅当去掉后缀 \(0\) 后两数相同。那么每段都是独立的子问题,因为段与段之间是无法合并的。对于每一段内,我们只关心后缀 \(0\) 的个数。考虑 \(dp_i\) 表示前 \(i\) 个数的答案。类似于消消乐的东西,考虑对于一个合并上来的计算它是从哪里合并上来的。\(f_{i,j}\) 表示以 \(i\) 为右端点,要向上合并 \(2^j\) 次的最短段中的左端点。\(f\) 可以对 \(dp\) 进行转移,时间复杂度 \(\mathcal O(n\log V)\)。
P11270
令 \(L=\sum |S_i|+\sum |T_j|\)。定义一个括号串的【和】为将左括号记作 \(1\),右括号记作 \(-1\) 后求和所得的值。
拆贡献,枚举 \(S_i,T_j\) 计算有多少个长度为 \(k\) 的 \(A\) 以 \(S_i\) 为前缀,\(T_j\) 为后缀,贡献均为 \(1\)。对于左括号视为 \(1\),右括号视为 \(-1\) 时,我们要求 \(S_i\) 的任意前缀和都 \(\ge 0\),否则这样的 \(S_i\) 没有用;对于左括号视为 \(-1\),右括号视为 \(1\) 时,我们要求 \(T_j\) 的任意后缀和都 \(\ge 0\),否则这样的 \(T_j\) 没有用。
先考虑 \(S_i,T_j\) 中间不存在新插入字符的情况,我们可以用 \(-1,1\) 用最小前缀和 \(=0\) 来进行判定。直接枚举所有的长度为 \(len\) 的重叠部分即可。考虑枚举 \(T_j\) 计算有多少个 \(S\) 合法。此时相当于给定了后面部分的最小前缀和,就要求 \(S\) 的和必须 \(\geq\) 某个值。你发现你是唐诗,因为最小前缀和完全不用管,你现在保留的 \(S,T\) 都是有希望合法的。两部分叠一起自然是有希望合法的,所以只需要判定 \(S,T\) 的总和是否 \(=0\)。直接用哈希刻画相等关系,记录此时 \(S\) 所有后缀 \([p,|S_i|]\) 的哈希值以及 \([1,p-1]\) 的和即可。把同个和的放到一起然后用哈希表维护,这部分时间复杂度 \(\mathcal O(L)\)。
再考虑 \(S_i,T_j\) 中间存在插入字符的情况,发现此时要做的是一个反射容斥。具体的,每个前缀可以刻画为点 \((x,y)\) 分别表示左括号,右括号的个数。如果出现 \(x<y\) 就寄了,每次移动是 \((x,y)\to (x,y+1),(x+1,y)\)。然后如果确定了 \(S,T\),起终点都是确定的,需要求的是 \((x_S,y_S)\to (k/2-x_T,k/2-y_T)\) 的方案数。此时就是总数减去穿过直线 \(y=x-1\) 的方案数。显然是可以拆贡献的。需要考虑的就是对 \(\binom{\Delta x+\Delta y}{\Delta x}-\binom{\Delta x+\Delta y}{by-1-ax}\) 求和。组合数是无法拆开的,考虑一些暴力的方法:我们可以说明,\((ax,ay)\) 以及 \((bx,by)\) 的本质不同个数各自有 \(\mathcal O(L^{2/3})\) 个。首先不考虑 \(y\) 是经典的 \(\mathcal O(\sqrt L)\) 个。只分析 \(x\leq y\) 的话我们贪心放置尽量多的本质不同的点,那么每次加入 \(x+y=t\) 的点即可,那么就是 \(\sum t^2\) 相关状物,因此可以分析出 \(\mathcal O(L^{2/3})\) 的上界。直接暴力匹配两端的等价类可以做到 \(\mathcal O(L^{4/3})\) 的。考虑进行根号分治减小等价类个数,可以将 \(x,y\leq \sqrt L\) 的点用 dp 推到 \(\sqrt L\) 的地方,这样有效减小了等价类个数。这样总时间复杂度 \(\mathcal O(L)\)。
20241117
20241117 T3
如果给定最终区间的一个情况,则这个情况必然是每个区间都是头接着尾,没有空隙地排列下去。我们找到那个所有线段都覆盖的那个点 \(P\)。为了简便处理,我们通过集体平移所有线段,然后使得 \(P=0\)。假如 \(n\) 为奇数,那么现在考虑在最终的结果中,存在一个最中间的元素。那么我们发现这个最中间的区间,往左边挪一挪往右边挪一挪,其余区间代价是不变的。所以这个区间在最优方案中一定是不动的。\(n\) 为偶数的情况,添加一个 \((0,0)\) 的区间,就也存在了一个这样的不动的区间。
设不动的那个区间为 \(Y\),左边的区间从左到右的序列为 \(P\),右边的所有区间从右到左的序列为 \(Q\),一个区间的长度为 \(r-l=len\)。我们从原先状态变化过来的得到的总代价为:
在确定哪些点是左边,哪些点在右边后,我们发现根据排序不等式,\(P,Q\) 中区间一定按照长度递减。我们枚举哪个区间是不动的区间,然后我们将所有点排好序后,考虑一个 DP。\(f_{i,j}\) 表示考虑前 \(i\) 个区间,我们放了 \(j\) 个区间在左边,复杂度立方,无法接受。由于 \(|P|=|Q|\),这样式子里面最后的贡献就一定为 \(len_Y×(n+1)/2\)。然后就不需要枚举那个中间的区间了。在 DP 中加一个 \(0/1\) 的维度表示目前是否已经选择了那个中间的区间。然后就可以 \(\mathcal O(n^2)\) 进行 dp。
P11292
考虑用管道取珠的套路,转化为独立有序选取两条长度为 \(l\) 的链,使得这两条链上所有点颜色相同的方案数。可以拆贡献,枚举所有长度为 \(l\) 的链的二元组,计算有多少染色方案使得其合法。那么就是令两个链的点交集为 \(S\),不难发现染色方案数为 \(k^{n-2l+|S|+1}\)。一个思路是求出所有的 \(|S|\) 有多少个方案然后进行统计,所以不难想到对公共点进行 dp,可以考虑容斥来做。\(f_{u,i,x,y}\) 表示 \(u\) 是钦定为的第 \(i\) 个公共点,此时第一条链是第 \(x\) 个位置,第二条链是第 \(y\) 个位置的选取链的方案数。预处理两点间长度为 \(k\) 的路径数量后可以做到 \(\mathcal O(n^2l^5)\) 的转移,此时有一个类似于二维 NTT 状物,可以进行分步转移优化到 \(\mathcal O(n^2l^4)\)。考虑从最终统计的角度入手,最终就是要统计钦定有 \(k\) 个公共点的方案数 \(g_k\),还原实际的 \(f_k\) 表示恰好有 \(k\) 个公共点,可以用二项式反演,最终答案为 \(\sum \sum f_j(-1)^{j-i}\binom{j}{i}k^{n-2l+1+i}\),可以化简为 \(k^{n-2l+1}\sum\sum(-1)^{j-i}\binom{j}{i}f_jk^i\),然后进行不断的参变分离类似状物可以最终化简为 \(k^{n-2l+1}\sum f_i(k-1)^i\)。因此可以在 dp 过程中每钦定一个就乘上 \(k-1\),略去钦定为第几个公共点的维度,仍然使用分步转移进行优化,时间复杂度 \(\mathcal O(n^3l+n^2l^3)\)。
20241118
QOJ7854
考虑把点放到圆上,边视作弦,那么就要求弦只在端点处相交,也就是说一条弦可以直接分割成内外独立的两个部分。钦定任意一个节点作为圆上的首个节点,之后乘 \(n\) 即可,放在圆的位置 \(p_i\) 就是其映射到的标号。考虑树的部分分,不妨设 \(p_1=1\),我们断言一个子树对应的是环上一段连续的区间,因此对于一个点相邻的所有边都可以确定与其相接的边的顺序,答案为 \(n\prod \text{deg}_i!\)。再考虑基环树的部分分,对于一个环而言它的相对顺序一定不会变的,交换会产生逆序对状物从而导致相交,同时环上挂的子树同样一定是环上的连续区间。如果原图是一个环,答案就是 \(2n\),考虑拓展。此时这个形态与无向图上环的关系比较大,因此可以考虑缩掉点双,建立圆方树。对于基环树的情况,我们只关心一个圆点相接的所有方点的相对顺序,将一条割边的两个点视作一个单独的点双也是可以的。此时的答案就是 \(2n\prod\text{deg}_i!\),其中 \(\text{deg}_i\) 表示在圆方树上圆点 \(i\) 的度数。考虑取模前答案 \(>0\) 的情况:对于一个点双连通分量而言,可以找出来一个环,满足这个环是极大的,那么此时我们断言不存在一个点不在这个环上,否则会出现一个点 \(u\) 连接了环上两个不同的点,此时 \(u\) 的两个边放到圆上时是必然产生交点的,对于这个极大环只有 \(2\) 种,有解时的总答案就是 \(2^cn\prod{\text{deg}}_i!\),\(c\) 为大小大于 \(2\) 的点双个数,即度数 \(>2\) 的方点个数。考虑如何判断有解,我们依然只需要考虑每个点双:判定是否有一个环包含了所有节点,并且环上的弦一定是不相交的。可以用广义串并联图方法,缩二度点过程中维护所有边,在此过程维护这个环的边。使用 std::map
维护的复杂度是 \(\mathcal O(m\log n)\)。
QOJ9604
显然子区间问题可以考虑分治,每次解决 \(l\in[L,mid],r\in(mid,R]\) 的所有区间 \([l,r]\) 的问题。有一个扫描线值域,维护当前最大值到中点的距离 \(p,q\) 的做法,此时可以用一个四维向量维护,因为对 \(p,q\) 的更新形如区间取 \(\min\),所以需要用到 \(\text{segbeats}\) 套矩阵维护,时间复杂度 \(\mathcal O(n\log^2n)\)。优化这个做法,同样考虑扫描线值域,\(a_i\leq x\) 的限制就转化为逐个更新。然后加入一个值 \(x\) 时就统计有多少个区间的最大值为 \(a_i\)。显然只有左侧区间的后缀最大值以及右侧的前缀最大值是有用的。对于快速合并两个有序序列可以做到单层 \(\mathcal O(r-l)\),扫描线加点是可以接受的,并且这些前缀最大值,后缀最大值可以用类似于单调栈的思想做到单层线性维护,这是因为一个点只会被一个唯一的点弹出一次。扫描线的维护值应该为 \(sum\) 表示当前所有区间的最大值之和。左右两侧的贡献与变化基本是对称的,不妨考虑加入的点在左边的做法:令左侧的后缀最大值位置分别为 \(P_0=l-1,P_1<P_2<\cdots<P_{x}=mid\),右侧的前缀最大值位置为 \(mid+1=Q_1<Q_2<\cdots<Q_{y}<Q_{y+1}=r\)。那么对于一个左侧后缀最大值而言,其贡献应该为 \(a_{P_i}(P_i-P_{i-1})(tr_{a_i}-mid-1)\),其中 \(tr_x\) 表示第一个右侧前缀最大值 \(>x\) 的位置。那么对于 \((P_i-P_{i-1})\),在动态插入删除单调栈时当然是可以维护的,问题在于右边的部分。实现结构应该是,先删去原有贡献,加上新贡献,更新右侧的 \(tr\)。考虑 \(tr\) 是有单调性的,并且是存在颜色段的,我们希望快速合并,也就是区间 \(\text{chkmax}\) 可以改成合并,统计长度,因此这个右边第一个比它大的位置可以用并查集维护,具体的,把贡献挂在 \(tr\) 上然后维护挂在它上面的 \(a_{P_i}(P_i-P_{i-1})\) 的和即可。时间复杂度 \(T(n)=2T(n/2)+\mathcal O(n\alpha(n))=\mathcal O(n\log n\alpha (n))\)。
P11291
dp 优化题,需要发掘一下转移的性质。
令 \(n=|T|\)。首先将字符串的限制转化掉,可以使用二分哈希的方法处理出 \(t[i:n]\) 与某个 \(S_i\) 的 \(\text{lcp}\),我们显然只关心 \(\max\),令这个最大值为 \(g_i\),那么就要求如果以 \(i\) 开头,那么这个 \(R\) 的结尾必须落在 \([i,i+g_i)\) 之中。先考虑如何判定合法,从前缀匹配是存在后效性的,但是可以转换维度,从后缀开始消。先考虑 \(70\) 分做法(我的赛时做法):注意到对于一个固定的 \(l,k\),合法的 \(r\) 是一段前缀,因此可以定义域值域互换,维护 \(f_{k,l}\) 表示对于固定的 \(k,l\),最大的 \(r\) 使得 \((l,r,k)\) 合法。转移考虑枚举 \(k\) 然后从 \(f_{*,k-1}\) 进行转移,可以倒序枚举 \(i\) 从 \(n\) 到 \(1\),然后树状数组维护 \([i,i+g_i)\) 中最大的 \(f_{*,k-1}\),可以做到 \(\mathcal O(nk\log n)\),第二问可以在此过程中维护区间加一次函数,进行离线并使用二次差分维护。
一个废话是 \(f\) 的具体值一定是某个 \(i+g_i-1\) 的值,对于 \(f_{l,k}\) 我们将这个 \(i\) 记作 \(R_{l,k}\)(\(R\) 是单词 \(\text{Real}\) 的简写,与题面中的 \(R\) 没有任何关系),即 \(f_{l,k}=g_{R_{l,k}}\)。考虑对这个 dp 进行优化,对于 \(k\) 很大时我们显然无法直接求,考虑发掘一下转移的性质,一个事情是你可以将 \(f\) 视为线段拓展一样的东西,就是要求从 \(l\) 拓展 \(k\) 次,每次拓展的左端点必须落在当前已有区间之中。显然你每次都会去贪心选取最优的转移点(即 \(j+g_j\) 最大的点),一个结论就是,在不考虑无法拓展时,每次选取的位置一定在新拓展的部分之中。证明是显然的,如果不在,在本次拓展你会直接选取这个点而不是在下一次拓展再选取。首先有 \(R_{i,1}=i\),其次考虑 \([i,i+g_i)\) 中的最大值位置 \(p\),那么就一定对于任意 \(k\) 有 \(R_{i,k}=R_{p,k-1}\),因为你其实可以看成是在左边拓展这个线段。
此时 \(k\) 的具体值是无用的,我们只关心从 \(i\) 开始不断跳 \(p\) 跳 \(k\) 次可以跳到哪里,不难想到建立边 \(i\to p\),此时这张图在不考虑根的自环时是个森林。\(R_{i,k}\) 即为 \(i\) 的 \(\min(\text{dep}_i,k)\) 级祖先。第一问就是对到 \(k\) 级祖先的路径的 \(g_{i}\) 进行求和,由于 \(k\) 是固定的,所以容易拆贡献进行一些分讨维护。第二问就是考虑在暴力时你会进行二次差分的修改,具体而言你会对于 \(x\in[l,r]\) 加上一个函数 \(y=(r-l+1)-(x-l)\),你会对二阶差分的数组进行四次单点修改。在前缀和意义也是容易维护的。时间复杂度 \(\mathcal O(n\log n+nm\log n)\)。
NOI2024 D2T2
显然要考虑 dp,最终需要求出的是 \(f_i\) 表示 \(i\to 1\) 的方案数,初始有 \(f_1=1\)。方便起见,令 \(h_u\) 的值表示 \(d_u-h'_u-1\),\(h'\) 是题面中读入的原始值。转移只需要考虑对第一次向上冲刺的位置进行转移,枚举 \(u\) 子树中的点 \(v\) 表示向下 \(u\) 休息到了 \(v\),枚举 \(u\) 的祖先之一 \(i\),如果满足 \(d_v-d_i\in[l_v,r_v]\) 且 \(d_i\leq \min_{j\in\text{path}(u,v)}h_j\) 就需要有 \(f_i\) 转移到 \(f_u\),不难通过枚举 \(v\) 并处理前缀和做到 \(\mathcal O(n^2)\)。
可以感受到,正解是几乎在线的数据结构优化问题,问题在于维护出所有 \(f_i\) 的系数 \(coef_i\) 使得 \(f_u=\sum coef_if_i\)。其中 \(coef_i\) 的意义就表示 \(u\) 子树有多少个 \(v\) 使得 \(f_i\to f_u\) 的转移是合法的。那么子树中 \(l_v,r_v\) 就相当于链 \(+1\),但是 \(h\) 让问题复杂了起来。为了去掉与区间 \([l,r]\) 的交集,我们尝试将更新改为对于 \(r_v+1\) 以上的 \(coef\) 进行 \(-1\),对于 \(l_v\) 以上的进行 \(+1\);\(h\) 的限制对两个操作独立,分别是 \(+1\) 和 \(-1\)。具体的,我们考虑 \(u\to1\) 的链,从前往后是深度为 \(0,1,\cdots,d_u\) 的点,构成一个长度为 \(d_u+1\) 的序列 \(s\),\(s\) 序列的每个元素是 \(h_i\),由不同的 \(R\in\text{anc}(u)\) 表示当前考虑到 \(f_R\),就会有不同的区间的 \(coef\) 被重置为 \(0\)。先考虑这个序列 \(s\),一个结论是我们只会关心所有的后缀最小值位置集合 \(P\),当找到 \(R\) 时,我们只关心 \(R\) 在这个序列中向后大于等于它的首个 \(P\) 中的元素,因此我们可以构造一个重构树,\(u\) 的父亲 \(up_u\) 表示 \(u\) 的祖先中最深的 \(v\) 使得 \(h_v<h_u\),显然这相当于跳了若干级祖先,重构树上的边代表着原树的一条直链,更新理应是链加。对于这两个限制可以分开考虑,不妨看到 \([0,p]\) 的操作 \(+1\),那么对于某个 \(u\) 其造成的就是 \([h_{\text{next}_u}+1,p]\)。所以我们可以找到 \(P\) 中首个 \(h<p\) 的位置打上 \([h+1,p]\) 的标记,后续的 \(\min\) 更新操作就与 \(p\) 无关了,给 \(h\) 打一个 tag 然后在重构树 dfs 时累加一下这个标记即可。后续的颜色视为 \(P\) 上那个点的即可。
现在的操作 \((x,y,w)\) 就是形如维护祖先序列中的 \(w\sum_{x\leq i\leq y}f_i\),可以使用差分的思想,差分成 \(x-1\) 处以及 \(y\) 处对于树上前缀和的修改,系数分别为 \(-w,w\)。这个操作赋上颜色 \(u\) 表示这是休息点为 \(u\) 的贡献,每次 \(f\) 只需要询问所有子树中颜色的 \(f\) 之和。树状数组维护,时间复杂度 \(\mathcal O(n\log n)\)。
P4426
广义串并联图方法的模板题,不再赘述。见 ZR3015。
P8276
一个显然的结论是,如果两个点之间存在一个无法走到环上的点,那么答案为 B。寻找无法走到的环上的点可以在反图上进行拓扑排序,被压入队列的所有点就是无法走到环上的点。这些点以及链接它们的边在朴素情况就是没有什么用的,可以直接删掉。对于一般图直接上手是不太好做的,考虑广义串并联图方法的拓展,从特殊位置入手:如果某个点 \(u\) 满足其出度恰好为 \(1\),那么考虑其指向的点是 \(v\),我们声称放棋子在 \(u\) 等效于在 \(v\),这是因为 \(u\) 在操作时必然只能走向 \(v\),这样可以直接对这两个点进行合并,我们认为,重边可以直接进行叠合,此时如果产生新的 \(1\) 度点就需要递归执行这个过程,启发式合并加队列来维护这个过程即可。不断进行合并,此时图的形态满足任意点出度 \(>1\)。此时由于任意点度数 \(>1\) 所以可以进行无限移动。使用 std::set
维护缩点的过程可以做到 \(\mathcal O(m\log^2n)\)。
WC2024 T2
显然的事实是如果对于 \([L,R]\) 问题合法,则对于任意 \([l,r]\subseteq [L,R]\) 的问题 \([l,r]\) 均合法,因此可以固定 \(l\) 跑双指针。首先注意到 \(L\) 的取值范围仅由所有的 \(a_i,a_{i+1}\) 决定,考虑一个 \(\mathcal O(n^2)\) 的 dp:固定 \(l\),扫描线 \(r\):维护一个 \(f_{i,0},f_{i,1}\) 表示停在 \(i\) 此时 \(L\) 的取值范围,每次形如区间的交与并进行操作。当两者均为空时就不合法。直接双指针需要用线段树维护矩阵来表示 \(f\),这是 \(\mathcal O(n\log n)\) 的。考虑使用 \(\text{baka's trick}\),即不删除双指针算法。维护指针 \(mid\) 以及 \(L_i\) 表示 \(f(i,mid)\),\(R=f(mid+1,r)\),那么当前双指针维护的信息 \(f(l,r)=f(l,mid)+f(mid+1,r)=L_l+R\)。做法就是外层循环 \(r\),如果当前 \(l>mid\) 就说明 \([mid,r]\) 是非法的,此时令 \(mid=r\),重置 \(R,L_*\) 的信息,此时向左推 \(l\) 直到非法。这样就是 \(\mathcal O(n)\) 次信息合并。本题中可以 \(\mathcal O(1)\) 实现信息合并。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App