1 条题解
-
0
题目解法分析
问题重述
有 个长度为 的非全零位串(),定义两个位串 和 的 Jaccard 相似度 为: [ \text{sim}(x, y) = \frac{\text{popcount}(x & y)}{\text{popcount}(x | y)} ] 其中 表示二进制中 的个数。
对于每个位串 ,计算它与所有位串(包括自身)的 Jaccard 相似度之和,结果对 取模。
算法思路
1. 关键公式变换
对于两个位串 和 ,设:
- (按位与中 的个数)
- (按位或中 的个数)
由集合论恒等式: [ \text{popcount}(x | y) = \text{popcount}(x) + \text{popcount}(y) - \text{popcount}(x & y) ]
因此: [ \text{sim}(x, y) = \frac{a}{\text{popcount}(x) + \text{popcount}(y) - a} ]
2. 问题转化
对于固定的 ,我们需要计算: [ \sum_{y} \frac{\text{popcount}(x & y)}{\text{popcount}(x) + \text{popcount}(y) - \text{popcount}(x & y)} ]
设 ,,。
则: [ \text{sim}(x, y) = \frac{a}{p + q - a} ]
3. 按交集大小分组
对于固定的 和交集大小 ,我们需要知道有多少个 满足 。
但是直接计算这个很困难,因为 依赖于 和 的交集。
4. 高维前缀和技巧
代码使用了 高维前缀和(SOS DP) 来计算:
- 第一次: 表示有多少个位串 满足
- 第二次: 表示有多少个位串 满足 ,并且乘以
5. 最终计算
对于每个 ,枚举交集大小 :
- 第一部分:
- 第二部分:$\sum_j \frac{1}{p + q - j} \times (\text{count}_j \times q)$
其中 是满足 的 的数量。
代码中通过两次高维前缀和分别计算这两部分。
算法步骤
-
预处理
- 计算每个位串的
- 预处理模逆元 用于除法
-
第一次高维前缀和
- 初始化
- 通过高维前缀和计算 表示有多少个 满足
-
第二次高维前缀和
- 初始化 $f[mask][\text{popcount}(mask)] = \text{cnt}[mask] \times \text{popcount}(mask)$
- 同样计算高维前缀和
-
合并结果
- 对于每个 ,枚举交集大小
- 计算:$\text{ans}[x] = \sum_j \left( \frac{j \times (p - j) + q}{p + q - j} \right) \times \text{count}_j$
- 其中 ,
复杂度分析
- 高维前缀和:
- 由于 ,,可以接受
- 总复杂度:
算法标签
- 高维前缀和(SOS DP)
- 位运算技巧
- 组合计数
- 模逆元
- 包含排除原理
这个解法通过高维前缀和高效计算所有位串对之间的交集信息,再结合数学变换将 Jaccard 相似度求和问题转化为可计算的形式,是一个典型的位运算+组合计数题目。
- 1
信息
- ID
- 3507
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者