标签:最大 sum 加法 方案 最小值 amp 个数 分配 空间
给定一棵有根树 \(T\),根节点深度为 \(1\),每个节点的深度为其父亲的深度 \(+1\),每个叶子节点的权值为其编号,现定义每个非叶节点的权值:
然后我们得到根节点的权值 \(W\)
对于一个叶子节点的集合 \(S\),我们现给集合 \(S\) 的点分配一个新权值 \(w_i\) 后,使得按照上述规则计算中 \(W\) 的权值改变,定义这个分配 \(w_i\) 的方案的权值为 \(\max_{i\in S}|i-w_i|\),\(w(S)\) 为所有方案中最小的权值。
设叶子节点数为 \(m\),对于所有的 \(2^m-1\) 个叶子节点集合,设 \(f(k)\) 为有多少个集合满足 \(w(S)=k\),给定 \(L,R\),求 \(f(L)+f(L+1)+...+f(R)\)
答案对 \(998244353\) 取模。
\(\rm Sol:\)
嘴巴 AC 一下...代码枯了
观察到答案要么变大要么变小。
如果答案要变小,那么我们肯定是将集合内所有元素都减去 \(k\)
然后统计有多少个集合可以使得答案变化。
不难发现我们求的大概是 \(\sum f(x)[x\le k]\),设为 \(g(k)\),差分一下就可以得到答案了。
但是 \(g(k)\) 直接求不太好求,因为实际上我们可以求出来的是有多少个集合满足变小后合法,变大后合法,存在一些集合满足变大/变小都合法。
他们是要减去的。
事实上那些集合满足变大/变小均合法也很好算,Dp 的时候维护 \(4\) 个数组就可以了 \(f_{u,0/1,0/1}\) 表示变大的情况下大于/小于,变小的情况下大于/小于。
于是就得到了一个 \(\mathcal O((R-L)\cdot n)\) 的算法。
具体 check 大概是对于某个 \(k\),对于变小的情况,假设 \(i-k<W\),那么设为 \(0\),否则设为 \(1\),那么取 \(\min\) 就是按位 \(\&\),取 \(\max\) 就是按位或,大于的情况同理。
进一步优化就考虑直接维护 \(\mathcal O(n)\) 个数组,设 \(f_{u,0/1,0/1,k}\) 表示对于 \(k\),考虑到点 \(u\) 的 \((0/1, 0/1)\) 情况下的答案。
不难发现转移其实是将数组对应部分乘起来并做加法的过程。
初始值也是插入在某个状态的一段区间内。
用线段树合并维护即可,要维护加法标记和乘法标记,复杂度 \(\mathcal O(n\log n)\),空间复杂度 \(\mathcal O(n\log n)\),会附带 \(4\) 的常数。
代码枯了。
标签:最大 sum 加法 方案 最小值 amp 个数 分配 空间
原文地址:https://www.cnblogs.com/Soulist/p/13638263.html