1 条题解

  • 0
    @ 2025-10-14 9:11:34

    好的,我们先来分析一下这道题和给出的代码。

    题目理解

    我们有一个 n×mn \times m 的表格,格子 (i,j)(i, j) 的值是 f[gcd(i,j)]f[\gcd(i, j)],其中 ff 是 Fibonacci 数列(f[0]=0,f[1]=1,f[n]=f[n1]+f[n2]f[0]=0, f[1]=1, f[n]=f[n-1]+f[n-2])。

    要求表格中所有数的乘积,对 109+710^9+7 取模。


    问题转化

    设 $P(n, m) = \prod_{i=1}^n \prod_{j=1}^m f[\gcd(i, j)]$。

    我们枚举 gcd(i,j)=d\gcd(i, j) = d,那么 gcd(i,j)=d\gcd(i, j) = d(i,j)(i, j) 对数是多少?

    i=dx,j=dyi = d \cdot x, j = d \cdot y,那么 gcd(x,y)=1\gcd(x, y) = 1,且 1xn/d,1ym/d1 \le x \le n/d, 1 \le y \le m/d

    所以:

    $$P(n, m) = \prod_{d=1}^{\min(n, m)} f[d]^{\sum_{x=1}^{n/d} \sum_{y=1}^{m/d} [\gcd(x, y) = 1]} $$

    指数上的计数

    指数部分:

    $$\sum_{x=1}^{n/d} \sum_{y=1}^{m/d} [\gcd(x, y) = 1] $$

    可以用莫比乌斯反演:

    $$\sum_{k=1}^{\min(n/d, m/d)} \mu(k) \cdot \left\lfloor \frac{n}{dk} \right\rfloor \cdot \left\lfloor \frac{m}{dk} \right\rfloor $$

    于是:

    $$P(n, m) = \prod_{d=1}^{\min(n, m)} f[d]^{\sum_{k} \mu(k) \lfloor n/(dk) \rfloor \lfloor m/(dk) \rfloor} $$

    进一步化简

    t=dkt = dk,则 dtd \mid tk=t/dk = t/d

    指数部分变成:

    $$\sum_{t=1}^{\min(n, m)} \left\lfloor \frac{n}{t} \right\rfloor \left\lfloor \frac{m}{t} \right\rfloor \sum_{d \mid t} \mu\left(\frac{t}{d}\right) \cdot [\text{指数上多了一个} \dots] $$

    其实更直接地,我们设 g=dg = dt=gkt = g \cdot k,那么:

    $$P(n, m) = \prod_{g=1}^{\min(n, m)} f[g]^{\sum_{k=1}^{\min(n/g, m/g)} \mu(k) \lfloor n/(gk) \rfloor \lfloor m/(gk) \rfloor} $$

    换元 T=gkT = gk

    $$P(n, m) = \prod_{T=1}^{\min(n, m)} \left[ \prod_{g \mid T} f[g]^{\mu(T/g)} \right]^{\lfloor n/T \rfloor \lfloor m/T \rfloor} $$

    代码中的实现

    代码中定义:

    s[T]=gTf[g]μ(T/g)s[T] = \prod_{g \mid T} f[g]^{\mu(T/g)}

    init() 函数里:

    • 先线性筛出 μ\muff(Fibonacci 数列模 109+710^9+7)。
    • 初始化 s[i] = 1
    • 对于每个 ii(即 gg),枚举倍数 jj,如果 μ(j)=1\mu(j) = 1,则乘 f[i]f[i];如果 μ(j)=1\mu(j) = -1,则乘 f[i]f[i] 的逆元。这实际上是在计算: [ s[j \cdot i] \times= f[i]^{\mu(j)} ] 因为 T=jiT = j \cdot ig=ig = iT/g=jT/g = j,所以 μ(T/g)=μ(j)\mu(T/g) = \mu(j)

    这样就能在 O(nlogn)O(n \log n) 时间内预处理出 ss 数组。


    查询部分

    查询时: [ P(n, m) = \prod_{T=1}^{\min(n, m)} s[T]^{\lfloor n/T \rfloor \lfloor m/T \rfloor} ] 利用数论分块,对 n/T\lfloor n/T \rfloorm/T\lfloor m/T \rfloor 相同的区间 [l,r][l, r] 一起计算: [ \prod_{T=l}^r s[T]^{\lfloor n/T \rfloor \lfloor m/T \rfloor} = \left( \prod_{T=l}^r s[T] \right)^{\lfloor n/l \rfloor \lfloor m/l \rfloor} ] 前缀积可以 O(1)O(1) 得到区间积,快速幂求幂次。


    算法标签

    • 数论
    • 莫比乌斯反演
    • Fibonacci 数列
    • 积性函数
    • 数论分块
    • 前缀积与逆元
    • 线性筛

    时间复杂度

    • 预处理:O(nlogn+n)O(n \log n + n)
    • 每次查询:O(n)O(\sqrt{n})(数论分块)

    对于 n,m106,T1000n, m \le 10^6, T \le 1000 是可行的。


    代码总结

    代码的核心是:

    1. 线性筛 μ\mu 和预处理 ff(Fibonacci)。
    2. 利用倍数枚举法计算 s[T]=dTf[d]μ(T/d)s[T] = \prod_{d|T} f[d]^{\mu(T/d)}
    3. 前缀积优化区间乘积。
    4. 查询时数论分块 + 快速幂。

    这样就能高效求出所有格子的 Fibonacci 值的乘积。

    • 1

    信息

    ID
    3058
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者