1 条题解

  • 0
    @ 2025-10-19 20:46:55

    题目解法分析

    问题重述

    NN 个长度为 KK 的非全零位串(K20K \le 20),定义两个位串 xxyyJaccard 相似度 为: [ \text{sim}(x, y) = \frac{\text{popcount}(x & y)}{\text{popcount}(x | y)} ] 其中 popcount\text{popcount} 表示二进制中 11 的个数。

    对于每个位串 xx,计算它与所有位串(包括自身)的 Jaccard 相似度之和,结果对 109+710^9+7 取模。


    算法思路

    1. 关键公式变换

    对于两个位串 xxyy,设:

    • a=popcount(x&y)a = \text{popcount}(x \& y)(按位与中 11 的个数)
    • b=popcount(xy)b = \text{popcount}(x | y)(按位或中 11 的个数)

    由集合论恒等式: [ \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. 问题转化

    对于固定的 xx,我们需要计算: [ \sum_{y} \frac{\text{popcount}(x & y)}{\text{popcount}(x) + \text{popcount}(y) - \text{popcount}(x & y)} ]

    p=popcount(x)p = \text{popcount}(x)q=popcount(y)q = \text{popcount}(y)a=popcount(x&y)a = \text{popcount}(x \& y)

    则: [ \text{sim}(x, y) = \frac{a}{p + q - a} ]

    3. 按交集大小分组

    对于固定的 xx 和交集大小 j=popcount(x&y)j = \text{popcount}(x \& y),我们需要知道有多少个 yy 满足 popcount(x&y)=j\text{popcount}(x \& y) = j

    但是直接计算这个很困难,因为 jj 依赖于 xxyy 的交集。

    4. 高维前缀和技巧

    代码使用了 高维前缀和(SOS DP) 来计算:

    • 第一次:f[mask][k]f[mask][k] 表示有多少个位串 yy 满足 popcount(mask&y)=k\text{popcount}(mask \& y) = k
    • 第二次:f[mask][k]f[mask][k] 表示有多少个位串 yy 满足 popcount(mask&y)=k\text{popcount}(mask \& y) = k,并且乘以 popcount(y)\text{popcount}(y)

    5. 最终计算

    对于每个 xx,枚举交集大小 jj

    • 第一部分:jjp+qj×countj\sum_j \frac{j}{p + q - j} \times \text{count}_j
    • 第二部分:$\sum_j \frac{1}{p + q - j} \times (\text{count}_j \times q)$

    其中 countj\text{count}_j 是满足 popcount(x&y)=j\text{popcount}(x \& y) = jyy 的数量。

    代码中通过两次高维前缀和分别计算这两部分。


    算法步骤

    1. 预处理

      • 计算每个位串的 popcount\text{popcount}
      • 预处理模逆元 inv[i]\text{inv}[i] 用于除法
    2. 第一次高维前缀和

      • 初始化 f[mask][popcount(mask)]=cnt[mask]f[mask][\text{popcount}(mask)] = \text{cnt}[mask]
      • 通过高维前缀和计算 f[mask][k]f[mask][k] 表示有多少个 yy 满足 popcount(mask&y)=k\text{popcount}(mask \& y) = k
    3. 第二次高维前缀和

      • 初始化 $f[mask][\text{popcount}(mask)] = \text{cnt}[mask] \times \text{popcount}(mask)$
      • 同样计算高维前缀和
    4. 合并结果

      • 对于每个 xx,枚举交集大小 jj
      • 计算:$\text{ans}[x] = \sum_j \left( \frac{j \times (p - j) + q}{p + q - j} \right) \times \text{count}_j$
      • 其中 p=popcount(x)p = \text{popcount}(x)q=popcount(y)q = \text{popcount}(y)

    复杂度分析

    • 高维前缀和:O(K2KK)=O(K22K)O(K \cdot 2^K \cdot K) = O(K^2 \cdot 2^K)
    • 由于 K20K \le 202K1062^K \approx 10^6,可以接受
    • 总复杂度:O(K22K+N)O(K^2 \cdot 2^K + N)

    算法标签

    • 高维前缀和(SOS DP)
    • 位运算技巧
    • 组合计数
    • 模逆元
    • 包含排除原理

    这个解法通过高维前缀和高效计算所有位串对之间的交集信息,再结合数学变换将 Jaccard 相似度求和问题转化为可计算的形式,是一个典型的位运算+组合计数题目。

    • 1

    「USACO 2024.12 Platinum」All Pairs Similarity

    信息

    ID
    3507
    时间
    3000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者