CF1641D

题面

给你 \(n\) 个集合 \(S_i\),每个集合有 \(m\) 个元素,集合 \(i\) 的权值为 \(w_i\) ,你需要求 \(\min\{S_i\cap S_j=\varnothing |w_i+w_j\}\)

数据范围:\(n\le 10^5,m\le 5\)

题解

首先,这个交为空就很难搞,对于这种有多个元素的集合做匹配我们都只能hash来判是否相等。

但是bitset就没有这种限制,如果我们给每个元素开一个 bitset,这样就可以对每一个元素 \(O(\frac{nm}{32})\) 的求出交不为空的,然后取反就是交为空的,为了求最小值我们可以最开始按 \(w_i\) 排序,这样就可以用 _Find_first()得到最小值。

但是这样就会有 \(O(\frac{nm}{32})\) 的空间复杂度,直接GG了,当然,如果你根号分治一波貌似空间也是可以卡过去的,但是实际上能不能过呢?小编也想知道。

这里主要介绍的是另外一种做法——容斥!

怎么个容斥法呢?

对于 \(S_i\) 来说,若 \(S_j\cap S_j\neq\varnothing\) ,那么 \(\sum\limits_{T\subseteq S_j}(-1)^{|T|-1} [T\subseteq S_i\and T\neq \varnothing]=1\)

这个的证明应该是二项式定理,就是考虑每个元素的贡献次数,和容斥的证明基本一样。

总之有了这个式子之后,因为加法的可加性,我们可以快速求出当前有几个集合和 \(S_i\) 有交,所以按 \(w_i\) 排序之后就可以二分求了。

但是为什么我们要给每一个 \(i\) 都求出对于的最小值呢?直接双指针就可以消除掉二分的 \(\log\)

扩展

如果题目给的是数列(也就是元素间有序)怎么办?

感觉可以按照[JOISC 2018 Day 4] 野猪 那样,但是初步想了一下发现也要 \(2^m\) 个状态,不知道能不能继续优化。

启发

  • 判断两个集合是否有交的方法。
  • 只要求全局最小值的时候是可以直接双指针的。
posted @ 2022-04-08 15:49  qwq_123  阅读(61)  评论(0编辑  收藏  举报