ZJOI2019 minmax 搜索

给定一棵有根树 \(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\) 的常数。

代码枯了。

posted @ 2020-09-09 13:37  Soulist  阅读(142)  评论(0编辑  收藏  举报