Solution Set #8
状态开始回暖了,但是还是好菜/kk
134 qoj3998. The Profiteer(背包,分治)
套用决策单调性的分治,查询最优端点的时候二分查找,可以做到 \(\mathcal{O}(nk\log^2 n)\)。
上面的做法是可以优化的:二分的时候把确定的范围直接加入,这样就是 \(\mathcal{O}(nk\log n)\) 的了。
https://qoj.ac/submission/304529
135 qoj1173. Knowledge Is...(贪心)
大力贪心,把所有区间按照 \(l\) 排序,如果能够匹配没有匹配的区间,那么直接匹配。否则,拆一个右端点最小的匹配,然后把当前区间和这个区间匹配。
可以使用线段树维护。但实际上如果一个匹配的左侧区间和右侧区间都能匹配,那么拆左边或者拆右边效果是相同的。
https://qoj.ac/submission/305547
136 qoj5357. 芒果冰加了空气(DP,计数)
考虑对于每个子树构造点分治方案,然后合并。
先考虑 \(u\) 为分治中心的时候连通块大小为 \(1\) 的情况。那么假设子树 \(v\) 中有 \(c_v\) 个连通块与 \(u\) 接触,那么方案数是 \(\binom{\sum c_v}{c_{v_1},c_{v_2},\cdots c_{v_k}}\)。否则,当 \(u\) 的联通块大小不为 \(1\) 的时候,我们可以考虑 \(v\) 的子树中有 \(d_v\leq c_v\) 个联通块层数比 \(u\) 浅,那么方案数就是把 \(c\) 换成 \(d\)。
直接在树上 DP,复杂度为 \(\mathcal{O}(n^2)\)。
https://qoj.ac/submission/306315
137 qoj6101. Ring Road(分治,最短路)
边分治,每次处理跨过两个联通块的最短路。
由于连接两个联通块的边只有 \(\mathcal{O}(1)\) 条,所以把这些边单独提出来跑最短路即可。
138 qoj970. Best Subsequence(贪心,整体二分)
发现如果相邻的两个数都 \(\leq \frac{W}{2}\),那么它们之间相当于没有限制。可以构造出一组解使得这些数全部被选上。把 \(>\frac{W}{2}\) 的元素选上,只需要在每个连续段选一个最小的即可,施调整法可以证明这样是最优的。
考虑整体二分 \(W\),从小到大扫描 \(W\),使用 set 维护 \(\leq \frac{W}{2}\) 的集合以及每个连续段的最小值,用树状数组做区间询问可以求出其中有多少个 \(\leq \frac{W}{2}\) 的元素和 \(>\frac{W}{2}\) 的元素。可以在外层循环 \(30\) 次来达到二分的效果。
139 qoj6638. Treelection
相当于限制除了 \(u\) 之外,其它每个结点不能放超过 \(sz_u-2\) 个票。
先不考虑 \(u\) 的特殊性,考虑贪心,每次把票放在最深的祖先上。维护 \(f_u\) 表示 \(u\) 子树内还有多少票,转移是 \(f_u=\max(\sum f_v-X,0)+1\),合法条件是 \(f_1=1\)。
假设 \(u\) 的子树也满足 \(sz_u-2\) 的限制,那么 \(u\) 的特殊性被消除,答案只和 \(sz_u-2\) 与最小合法 \(X\) 的大小关系有关,可以二分求出 \(X\)。否则,我们需要额外考虑 \(X=sz_u-1,f_1=2\) 的情况。此时我们需要判断 \(f_1\) 中多出的票能不能删去,合法条件即为对于 \(u\) 的所有祖先 \(anc\) 都有 \(f_{anc}>1\)。
140 qoj6540. Beautiful Sequence(贪心)
钦定集合 \(S,T\) 使得 \(S\) 为满足条件的元素而 \(T\) 不是。
考虑判断合法,将 \(S\) 中元素去重并从大到小排序,\(T\) 中元素从大到小排序,那么合法条件是 \(T_i\leq \min(S_i,S_{i+1})\)(如果不存在元素,则视作 \(-\infty\))
考虑先钦定 \(S\) 是全集,从 \(S\) 中删去元素使得合法,最终的目标是最小化 \(T\) 中元素个数。注意到最终的 \(T\) 满足 \(|T|=|S|-1\)(\(|T|\) 是可重集),而对于一次删除操作,如果我们删去的元素是最后一个,那么 \(|T|\gets|T|+cnt_u\),\(|S|\gets |S|-1\),否则,\(|T|\gets|T|+cnt_u\)。注意到前者是更优的,所以我们会贪心选 \(cnt_u\) 尽量小的元素。所以可以把所有数按照 \(cnt_u\) 排序,从小到大能选则选。可以证明这样是正确的(考虑唯一的问题是我们选了一个出现次数较少但值较大的元素,可能影响后面的判断,但其实可以大力调整)。
暴力实现可以平方,考虑优化判断的过程。注意到我们把 \(T\) 中的元素看作数轴上的一个 \(-1\),\(S\) 中的元素看做 \(1\),条件相当于折线始终不会碰到 \(y=0\)。线段树维护即可。
141 2024.1.16 cheer(差分,gcd)
注意到差分之后 \(\gcd\) 不变,考虑差分。差分后一次操作只会改变 \(4\) 个点的权值。
任意选 \(5\) 个点,答案一定是这 \(5\) 个点点权的 \(\gcd\) 的因数。对于它的每个素数因子 \(p^k\) 考虑。分类讨论:
- 没有点不被 \(p^k\) 整除,直接加。
- 恰好 \(2\) 个点被 \(p^k\) 整除,那么只有修改祖先链才有用。
- 恰好 \(4\) 个点被 \(p^k\) 整除,那么只有确定的路径有用。
所以我们只需要考虑 \(\log V\) 条路径的答案,暴力即可。
142 2024.1.17 tree(MST,边分治)
大力 boruvka 可以得到 \(\mathcal{O}(n\log^3 n)\) 做法。
考虑大力优化这个做法。注意到瓶颈在于边分治中的排序,而每次 boruvka 排序的过程是相同的。所以可以直接把分治过程离线,求最短边的部分双指针解决。复杂度 \(\mathcal{O}(n\log^2 n)\)。
143 CF1158E Strange device(树交互,并行操作)
操作明示把树分层。
考虑二分,每次询问出距离 \(l\) 不超过 \(mid-l-1\) 和 \(mid-l\) 的结点,那么可以把点分成 \([l,mid),[mid,mid],(mid,r]\) 三类。
考虑并行,每次找到所有二分的区间,一次把所有奇数或所有偶数的区间割开,可以做到 \(4\log n\) 的操作次数。
然后询问每一层,可以按照模 \(3\) 的余数分层,然后二进制分组一下,然后并行一下,就可以做到 \(3\log n\) 了。
https://codeforces.com/contest/1158/submission/242177866
144 qoj962 Thanks to MikeMirzayanov(排序,构造)
先转化一下操作:区间翻转,然后再全局翻转。
一个套路:先考虑给 \(01\) 排序,然后通过分治将问题转化成给 \(01\) 排序。
考虑怎么给 \(01\) 排。先把一个连续段缩起来,然后问题是给 \(01010101\cdots\) 排序,我们把第奇数个 \(01\) 对翻转,偶数不变,每次可以让连续段数量减半。所以可以在 \(\log n\) 时间排序 \(01\)。
回到原题,我们分治下去,然后并行操作,可以做到 \(\log^2 n\) 次操作,常数较小,但是还是要卡一下。
https://qoj.ac/submission/307627
145 JOI Open 2019 Triple Jump(线段树,支配对)
在单调栈上观察,可以发现只有在单调栈过程中相邻的两个 \((a,b)\) 有用,所以原问题 \((a,b)\) 的支配对数量是 \(\mathcal{O}(n)\)。
但是带上 \(c\) 则还需要一个后缀 \(\max\) 操作。挂到线段树上观察,相当于维护二元组 \((A_i,B_i)\):
- \(B_i\gets \max(B_i,A_i+x)\)。
- \(A_i\gets \max(A_i,x)\)。
- 区间询问 \(B_i\) 最值。
直接使用线段树是可以维护的。
146 NOI 2020 超现实树
好像没那么难?
先考虑链的包。要求对于左右儿子均可以生成,分类讨论:
- 如果存在一棵树是单点,答案是 Almost Complete。
- 否则,把只有左儿子的链往左递归判断,只有右儿子往右递归判断。
一般的情况只需要额外考虑有两个儿子的情况。考虑一个构造非法解的方式:左儿子挂一个单点,右儿子递归构造。此时集合 \(\mathcal{T}\) 中能够用来生成右儿子的树的个数是最少的,即满足左儿子是单点的树。把这些树拿出来递归处理即可。
147 QOJ 1436 Split in Sets(贪心)
先考虑 \(a_i=2^k\) 的做法,那么如果最高位有 \(\geq k\) 个那么一定是铺满,然后剩下的数全部放一个里面。
可以得到一个结论:如果最高位有 \(\geq k\) 个,那么一定只有一个桶的 and 值不是最高位。因为如果多个最高位堆一起,可以把两个较低位合并然后把最高位单独拉出来。较低位的影响是 \(a+b-a \text{ and } b=a \text{ or } b\),不会比增大的值还大。
注意到如果所有数最高位都相同,那么可以把最高位删去,然后直接把最高位的贡献计算。
根据上述性质,设计 \(\text{solve}(a,k)\) 表示求解的算法。
- 所有数最高位相同,计算最高位贡献,递归。
- 计算最高位数的数量 \(cnt\),若 \(cnt<k\),那么选 \(k\) 个位置把最高位单独放,其余数递归下去。
- 否则,其它数一定放在同一个桶里面,把它们与起来变成一个数,计算最高位贡献,递归。
计数是简单的。
https://qoj.ac/submission/309735
148 2024.1.22 模拟赛 emotion
问题约等于对 \(n\) 的所有子集 \(S\) 求生成树个数 \(f(S)\)。
有转移式子:
可以使用子集卷积优化到 \(\mathcal{O}(2^nn^2)\)。
149 qoj2065. Cyclic Distance(凸优化)
考虑确定点集之后怎么做,可以拿重心构造出两倍虚树大小。
考虑 DP,加一条边的贡献是 \(\min(i,k-i)w\),合并子树是 \((\max,+)\) 卷积,所以是凸的,跟 THUPC 那题一样拿对顶堆维护一下就好了。