ARC196
AtCoder Regular Contest++ 196
闲话
是 VP 的,主要是训一些四个题的节奏偏慢的比赛,还有就是下周日有 ARC++,而我之前两场这个东西打的都不是太好。
因为是 VP 所以放飞了不写拍子也不考虑极端数据,你甚至可以看到我一开始把 \(\mathcal{O}(n^2)\) 的 C 题代码交上去验证正确性,所以多罚了几发。
无所谓,题目很好,很有启发性,那就够了。
A (贪心、分类讨论、*1200):
被对顶堆阴了一手。
首先考虑如何贪心,有一个非常简单的区间 \(\rm DP\),大概就是 \(f(l,r)\) 表示删除 \(l,r\) 对应的最大权值那么转移可以是 \(f(l,r) \to f(l-1,r+1)\) 或者对 \([l,k],[k+1,r]\) 合并为 \([l,r]\)。不难注意到区间可以合并的条件是两侧长度均为偶数,然后没了。所以如果 \(n\) 是偶数那么必定能删空,每个点又既可作左括号又可作右括号,则答案就是前 \(\frac{n}{2}\) 大的权值减去后 \(\frac{n}{2}\) 大的权值。直接按照权值从大往小归纳构造就可以说明充分性。具体就是将 \(a\) 升序排序后 \(\sum\limits_{i=n/2+1}^{n} (a_{i} - a_{i-n/2})\)。然后因为任意时刻都是偶数长度,并且每次恰好删去一个 \(1 \sim n/2\) 和一个 \(n/2 + 1 \sim n\),所以此时必定有一对 \(a_i,a_{i-n/2}\) 是相邻的(不然只可能是有一侧完全被删空,这又与上面的删除变化量不符)。那么归纳必定是成立的。
然后你考虑 \(n\) 为奇数怎么做,最后肯定会剩下来一个数,并且这个数的下标必定是奇数。否则两侧必定有一边长度为奇数无法删空。那你考虑对每个奇数位置 \(i = 1, 3, 5, \dots, n\),求出 \(p_i\) 和 \(s_i\) 分别表示 \([1,i-1]\) 和 \([i+1,n]\) 的子问题,这个做法就和上面偶数一模一样。具体要求出所有 \(\mathcal{O}(n)\) 个 \(p_i\) 你考虑直接对顶堆维护,每次 \(i - 2 \to i\) 的过程中加进去 \(a_{i - 1}\) 和 \(a_{i - 2}\) 即可,\(s_i\) 同理。
注意对顶堆需要对两侧调整,不能说因为 \(k\) 单调递增就只维护一侧,因为你此时还需要考虑左侧最小值和右侧最大值的大小关系,不能只保证两侧大小符合条件。
时间复杂度 \(\mathcal{O}(n \log n)\)。
B (并查集、二分图、*2200):
省流:比 A 简单一点。
主要是比较套路,考虑将网格图的每条边按照中点是否有痕迹分个类,注意到 A 类瓷砖对应的限制是对边在不同类,B 类瓷砖对应的限制是邻边在不同类,于是直接拆虚点用扩展域并查集维护即可。也即对每块砖拆出 \(u,d,l,r\) 四个点分别对应四条边,A 类就是 \((u,\neg d), (d,\neg u), (l, \neg r), (r, \neg l)\) 连边,B 类就是 \(u\) 和 \(d\) 分别与 \(\neg l, \neg r\) 连边,以及 \(l,r\) 分别与 \(\neg u, \neg d\) 连边。
因为是下标在模意义上的网格,所以这样拆出来一共有 \(2nm\) 个点,最终因为每个等价类内部一致只能整体翻转/不翻转,又因为 \(i\) 和 \(i + n\) 对应的等价类必定是镜像的,所以只需要求出等价类数量 \(k\),答案即为 \(2^{k/2}\)。
时间复杂度 \(\mathcal{O}(nm \times \alpha(nm))\)。
C (容斥原理、分治 NTT、*2900):
比较典但是比较好的题。
可以抽象为一条从左向右连边的链,每次确定黑白点等价于,连一条反边或者覆盖一段路径。那么强连通等价于存在一条从 \(2n\) 走到 \(1\) 的路径。因此如果 \(s_1 = \texttt{W}\) 或者 \(s_{2n} = \texttt{B}\) 那么肯定寄了。
否则我们可以 \(\rm DP\),设 \(f_i\) 表示 \(i\) 到 \(1\) 的子图是强连通的方案数,那么转移类似于找一个 \(j \lt i\) 然后从区间 \([j + 1, i]\) 中,至少选一个点与 \([1,j]\) 中的点连边。然后你发现正着做这个东西等价于对一个可以按规则加边的图求类似于 DAG 划分的东西,做不了一点。
但你发现可以把所有边分为正向和反向的,它比一般图甚至弦图的性质都要好,所以大概是可以做到多项式的。考虑正难则反,一个方案是不合法的当且仅当它可以被分为 \(k \gt 1\) 段区间 \([l_1,r_1], [l_2,r_2], \dots, [l_k,r_k]\) 使得每一段区间都是极大的强连通分量。也就是不存在任何一条形如 \(u \to v\) 的边,使得 \(u \in [l_{i+1},r_{i+1}], v \in [l_i,r_i]\)。这样就可以从前缀入手了,大概就是找到第一个合法前缀对应的 \(j\) 那么 \((j,j+1)\) 之间有分界点,每次对着这个顺序转移就可以确定不重。
那么这样的 \(j\) 必定是白点,而且前缀中所有黑点都需要和前缀中的白点匹配,否则和后面匹配就形成一条反边那这个分界点就无效了。又因为是你构造分配方法所以只需要确保前缀中白点数目多于黑点即可。剩下来的白点是可以任意与 \([j+1,i]\) 中的黑点相连的,假设是有 \(x\) 个白点,\(y\) 个黑点那么系数就是 \(\binom{x}{y} \times y!\) 状物。因为 \(j\) 对应前缀内已经匹配了 \(y_j\) 对点,所以剩下来 \(x_j - y_j\) 个白点要和 \([j+1,i]\) 中的一共 \(y_i - y_j\) 个黑点匹配,所以转移就是
然后这个直接做是 \(\mathcal{O}(n^2)\) 的。可能边界有点,还有就是递推组合数的下标范围是两倍这个需要注意一下。
现在优化这个东西,这种带组合数贡献的容斥贵物显然无法直接转成某个生成函数解决,但是你注意到从 \(f_j\) 的角度看贡献到的下标方向是不降的,所以可以考虑分治 NTT。具体就是把所有组合数拆开最后是形如
状物,这个是经典半在线卷积形式,从 \([l,m]\) 往 \([m + 1, r]\) 贡献然后把 \(f_j\) 放到 \(y_j\) 对应的位置上和阶乘卷积即可。时间复杂度 \(\mathcal{O}(n \log^2 n)\)。
浙公网安备 33010602011771号