zr 暑假集训
1A
https://www.cnblogs.com/dcytrl/p/18995726 P10831。
2A
一个重要的观察是发现我们只关注乘积,将乘积质因数分解后每个质因子的贡献是独立的,而假设质因子 \(p\) 的次数是 \(c\),那么贡献就是求 \(x_i\ge 0,\sum x_i=c\) 的方案数,就是插板法 \(\binom{n+c-1}{n-1}\),线性筛预处理出来你想要的信息即可。注意空间常数和时间常数。
2C
将 \(a_i\) 自加 1,一个重要的性质是 \(ans=\max_{i=1}^n\lceil\frac{cnt_i}{i}\rceil\),其中 \(cnt_i\) 是指 \(a_j\le i\) 的 \(j\) 数量。证明可以感性理解一下,对于 \(i\) 来说,要将 \(\le i\) 的数全匹配完就至少需要 \(\lceil\frac{cnt_i}{i}\rceil\) 个娃,将所有 \(i\) 取一个最大值就是答案,在感性理解一下一定能取到下界。
考虑维护这个东西,由于每次插入一个数 \(ans\) 只会加一,所以考虑维护什么时候 \(\frac{cnt_i}{i}> ans\),假设为了到达 \(\frac{cnt_i}{i}\ge ans+1\) 还需要再减 \(d_i\)(这里的意思是,\(cnt_i+d_i=i\cdot ans\)),那么插入一个数就相当于后缀加,然后碰到负数就精确定位到那个负数然后给他加上其下标即可,由于每个数 \(\frac{cnt_i}{i}\) 的变化总量是调和级数,所以复杂度是两个 log 的。但注意到 \(\frac{cnt_i}{i}\ge ans\rightarrow i\le \frac{cnt_i}{ans}\le\frac{n}{ans}\),这说明当当前答案为 \(ans\) 时 \(\frac{n}{ans}\) 之后的元素再也派不上用场了,这样每次 \(ans\) 增加暴力重构 \([1,\frac{n}{ans}]\),然后后面的元素想点办法让它们永远没贡献即可。由于线段树点数为 \(O(n)\)(虽然该题情景下线段树点数其实是 \(O(n+\log n)\) 的,但是问题不大),总重构复杂度 \(O(n\log n)\),所以总复杂度 \(O(n\log n)\)。
3A
首先将题意转化为每种质因子不能出现 \(\ge k\) 次,然后推一推可以发现选的数不能拥有超过三个质因子(否则拆成两个质因子的数更优),如果有两个质因子那么次数必须都为 1(否则减少次数更优),这样选的数只能是两个质因子相乘或一个质因子的幂次的形式。发现选质因子幂次更优,先贪心选这个。然后,贪心的让每个质因子跟最大的能跟它匹配的数匹配,这样就能节省出更多的小数用于更多的匹配。复杂度线性。
3C
有一个显然的贪心是将元素降序排序,然后挨个询问特殊石子在不在那个堆里,答案即为 \(\max_{i=1}^n i-[i=n]+\lceil\log_2a_i\rceil\)。然而根据样例可以发现答案是可能变的更小的,稍微推一推或者猜一猜可以发现答案减少量至多为 1。并且可以发现,此时的方案是将某一堆中取出前 \(2^{highbit}\) 个询问存在性,如果存在那么直接在这一堆里二分,此时如果石子数不是 2 的幂次那么操作数会减少一,然后将剩下的石子作为一个新堆扔到后面处理。根据贪心结论,特殊操作的堆必然是 \(\lceil\log_2a_i\rceil\) 中石子数最小的堆。直接模拟复杂度就是 \(O(qnm)\) 的。
为了维护方便,将原本答案里 \(-[i=n]\) 这一项去掉,等着来减一,这样显然不会改变最终答案。首先,找出每种 \(\lceil\log_2a_i\rceil\) 中石子数最小的堆和总堆数,这需要预处理 ST 表和前缀和实现。按照 \(\lceil\log_2a_i\rceil\) 从大往小处理,如果它顶到答案上界了,那么我们尝试将其减少 1,就按上面说的执行,把剩下的元素扔到底下的类里,然后更新石子数最小的堆。此时需要支持查询两个序列相同长度的后缀的字典序,类似 SA 那样基排即可(当然这个也需要在 ST 表用到),注意特判二的幂次的特殊情况,它比任何与它同一类的数都大。如果中途发现某一堆答案大于 \(ans\),那么说明判定失败,不能减 1。时间复杂度 \(O((n+q)m)\)。
5A
我咋连这个都不会了啊????
每次操作相当于把第一个元素丢到任意位置上,考虑当操作次数取到最小值时,碰到一个数时,拿出最长上升后缀,然后将该值插入到这个最长上升后缀内。推广到一般情况,发现转移只与最长上升后缀的长度有关,设 \(f_{i,j}\) 表示前 \(i\) 次操作,最长上升后缀长度为 \(j\) 的方案数,转移考虑补全最长上升后缀 \(f_{i,j}\rightarrow f_{i+1,j+1}\),或者放前面不影响改变 \(f_{i,j}\rightarrow f_{i+1,j}\cdot (n-j)\),或者放后面减小最长上升后缀的长度 \(f_{i,j}\rightarrow f_{i+1,k},1\le k<i\),当第一个数比最长上升后缀的第一个元素小时情况有些特殊,但推一推就可以发现贡献系数不变,直接转移复杂度平方。
5B
首先能显然写出一个费用流模型,并可以使用前缀优化建图,但是前途有限,模拟费用流可能不太好想/好做。
先考虑如何满足最大匹配的限制。将 0 写成 1,将 1 写成 -1,将其做前缀和,设为 \(s\),那么完全匹配后肯定剩下了前面一段 1 和后面一段 -1,最大匹配数就是总 1 的个数减去剩下的 1 的个数,而前者是常量,那么目标就是最小化后者,而后者就等于 \(\min_{i=0}^n s_i\)。原题也可以转化为选出 \(k\) 对 \(a_x=a_y\) 的 \((x,y)\),使得钦定选择这些区间后 \(\min_{i=0}^n s_i\) 不发生变化,而匹配 \((x,y)\) 就相当于将 \(x,y\) 上的值变成 0。也就是说,对于每个 \((x,y)\),将 \([x,y)\) 区间减 1,然后在最小值不变的前提下最大化 \(k\)。
此时有结论:对于每种颜色,将其像括号序列那样用栈做匹配,得到 \(O(n)\) 对 \((x,y)\),最终的答案一定在这之中。证明可以考虑调整法。据此,我们就直接按照左端点排序贪心选即可,直接线段树维护复杂度固然是一个 log 的,但是我们可以通过 set 实现:先钦定所有点对都选,此时从左往右扫,如果当前 \(s_i\) 低于原先的最小值,那么就需要删除,删除肯定贪心的选择右端点更大的删,然后等扫到右端点时如果还没删那就是答案。复杂度也是一个 log,但好写很多,也快很多。
5C
分成两种情况讨论。
\(2m\le n\)
这种情况所有长度为 \(m\) 的区间的交集为空,稍微推一下,初始有一颗大小为 \(m\) 的子树,最终也有一颗大小为 \(m\) 的子树,由于 \(2m\le n\),所以对于这两个子树根之间的路径,路径上的点不能有支路(否则必然存在一个时刻不能连通)。事实上,这便是有解的充要条件。由于 \(n\) 较小,完全可以枚举这两个子树根,而不难发现只有至多一对可能的答案,此时贡献是两棵子树内的拓扑序(子树内的贡献相当于要让根节点的消失时刻晚于儿子们或出现时刻早于儿子们),由于翻转是另一种答案,所以注意乘 2。
\(2m>n\)
这种情况所有长度为 \(m\) 的区间的交集大小为 \(2m-n\),中间这 \(2m-n\) 个点永远不会变动,而这 \(2m-n\) 个点必然构成一个连通块,这个连通块将原树分成若干部分,每部分的子树大小不超过 \(n-m\)。由于 \(2m>n\),所以 \(n-m<\frac{n}{2}\),所以重心必然在这个连通块内,不妨让重心为根。还要满足题意,那么说明删点还是从叶子剥起,加点还是从子树根加起,还是拓扑序。而我们要做的就是选出若干个不相交的子树,并把他们划分成两个集合,每个集合子树大小之和为 \(n-m\),集合内部贡献就是子树内部的拓扑序以及子树间的排列顺序,都是简单组合数,直接在 dfn 序上 dp 即可,只需要设 \(f_{i,j,k}\) 表示考虑到 \(i\) 子树,两个集合总大小为 \(j,k\) 的方案数,转移只有三种,所以复杂度 \(O(n^3)\)。
6A
将三角形的面积用叉积表示,为了让符号正确,你需要钦定三个点在圆上的顺序,瞎拆一拆贡献即可,答案是精确的。复杂度 \(O(n)\)。
6B
放两个位置之一,显然是 2-sat,看到树上距离拍上去一个边分治就行(点分治比较难写),然后将子树内按照深度排序,然后后缀优化建图即可。复杂度 \(O(n\log^2n)\)。
7A
设 \(dp_i\) 表示选 \(i\) 的方案数,考虑儿子 \(u\) 向父亲合并,如果 \(u\) 不在某条链的端点或 lca 处,那么选了 \(i\) 就必须选 \(u\),否则可以考虑不选 \(u\)。
现在考虑怎么求每个点是否在某条链的端点或 lca 处,可以不要脑子的直接拍上去一个 tarjan lca 做到线性,更高明的做法是对每条链赋随机权值做异或哈希,然后染整条链只需要树上差分。
8A
注意到 \(k\) 很小且转移可以用矩阵乘法表示,考虑设 \(f_i\) 表示前 \(i\) 个点任意选的矩阵之和,由于矩阵有结合律,所以转移直接乘上转移矩阵的 \(b_i\) 次方即可,然后别忘了让 \(f_i\) 带上 \(c\) 的系数,也是好处理的。现在要求固定矩阵的 \(p\) 次方,如果二进制拆分那就太逊了,为了减少复杂度,我们可以调整进制数以减少时间消耗,取 \(p=2^8\) 时间复杂度 \(O((n+p)\log_pVk^3)\)。
8B
如果值域足够小我们可以枚举中位数然后判定一下中位数大于等于枚举的值的方案数,然后计算贡献。回到原题,由于只需要 \(ans_0\le ans\le 2ans_0\),意味着我们可以将每个数扩大到两倍以内,考虑将 [1,2] 都变为 2,[3,6] 都变为 6,以此类推,这样只有 \(O(\log n)\) 种值,直接 dsu on tree 复杂度是 \(O(n\log^2n)\) 的,但是由于权值为正负 1,所以最大值域不会超过链长,可以长剖,维护负数区的后缀和、正数区的前缀和和零点位置即可。复杂度 \(O(n\log n)\)。
9A
就是求有多少个连通块满足连通块内的区间有交。由于有交,所以点边容斥一下变成都包含某个点的连通块数-包含某个 \((i,i+1)\) 的连通块数,暴力做显然是直接树上 dp,扫描线+动态 dp 可以做到两个 log 或一个 log,线段树合并可以更简单的做到一个 log。
10A
注意到一个区间被执行了一操作以后该区间永远都是不降区间了,同理二操作也会导致一段区间永远不升。于是可以直接套用颜色段均摊维护这坨东西,需要写一个区间推平,复杂度 \(O(n\log n)\)。
10B
按照题意可以写出一个网络流模型:分 \(k\) 层,\(a_i\) 层的 \(i\) 点向下一层的该点连边,第 \(k\) 层 \(a_i=k\) 的点向 \(T\) 连边(以上流量都是 1),\(S\) 向第一层第一个点连边,每一层中间 \(i\) 向 \(i+1\) 连边(以上流量都是正无穷)。最大流转最小割,考虑模拟最小割,显然只会割 \(a_i\) 层 \(i\) 向下一层的 \(i\) 连的边,并且手玩可以发现肯定是第一段割 \(a_i=1\) 的,第二段割 \(a_i=2\) 的,以此类推,证明可以调整。然后用线段树瞎维护维护即可,复杂度 \(O(q\operatorname{poly}(k)\log n)\)。

浙公网安备 33010602011771号