针对 LeetCode 3725,Golang 实现同样采用容斥原理(逆向统计),利用最大值只有150的特点高效求解。

核心思路

1. 预处理因子表:枚举 1..150,对每个倍数记录因子。
2. 统计每行倍数计数:对每行统计能被 d 整除的数字个数 cnt[row][d]。
3. 计算倍数方案数:mul[d] = ∏ cnt[row][d],即每行选出的数都是 d 的倍数。
4. 容斥求恰好GCD=1:从大到小遍历 d,exact[d] = mul[d] - sum(exact[2d], exact[3d], ...)。答案即 exact[1]。

Golang 实现代码

```go
const MOD = 1_000_000_007

func countCoprime(mat [][]int) int {
    m := len(mat)
    maxVal := 150
    
    // 1. 预处理因子
    factors := make([][]int, maxVal+1)
    for d := 1; d <= maxVal; d++ {
        for multiple := d; multiple <= maxVal; multiple += d {
            factors[multiple] = append(factors[multiple], d)
        }
    }
    
    // 2. 统计每行每个因子的出现次数
    cnt := make([][]int, m)
    for i := range cnt {
        cnt[i] = make([]int, maxVal+1)
        for _, num := range mat[i] {
            for _, d := range factors[num] {
                cnt[i][d]++
            }
        }
    }
    
    // 3. 计算 mul[d]:所有数都是 d 的倍数的方案数
    mul := make([]int, maxVal+1)
    for d := 1; d <= maxVal; d++ {
        ways := 1
        for i := 0; i < m; i++ {
            ways = ways * cnt[i][d] % MOD
            if ways == 0 {
                break
            }
        }
        mul[d] = ways
    }
    
    // 4. 容斥:从大到小计算 gcd 恰好为 d 的方案数
    exact := make([]int, maxVal+1)
    for d := maxVal; d >= 1; d-- {
        sum := mul[d]
        for multiple := d * 2; multiple <= maxVal; multiple += d {
            sum = (sum - exact[multiple] + MOD) % MOD
        }
        exact[d] = sum
    }
    
    return exact[1]
}
```

复杂度分析

· 时间复杂度:O(m * n * τ + V * log V),其中 V=150,τ 为每个数的因子数(平均约12个),完全可接受。
· 空间复杂度:O(m * V),主要存储每行的因子计数。

关键点说明

· 由于数值范围固定为 1..150,预计算因子表是最高效的方式。
· 容斥从大到小计算,保证 exact[multiple] 已经计算完毕。
· 模运算使用 (sum - exact[multiple] + MOD) % MOD 处理负数。

这种方法比直接枚举所有组合快得多,利用了数值范围小的特性进行反向计算。

 

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐