HNOI 2002 跳蚤 容斥,莫比乌斯反演

HNOI 2002 跳蚤 容斥,莫比乌斯反演

题意

一只跳蚤目前站在无限长的绳索中央,给出一张卡牌,上面有(n+1) 个自然数,其中最后一个数字为(m)

跳蚤可以选择卡牌给的数字跳任意次,只要最终能够到达左边(1) 单位即可。

现在给定(n,m) ,问有多少张卡牌可以满足要求

[n,mleq 10^8,m^nleq 10^{16} ]

分析

一张牌能够跳到最左端,需要满足

[sum a_ix_i = 1 ]

根据裴蜀定理,该方程要有解等价于

[(a_1,a_2...a_n,a_{n+1})=1 ]

那么答案就可以写成

[sum _{a_1=1}^msum _{a_2=1}^m...sum _{a_n=1}^m[gcd(a_1,a_2...a_n,m) = 1] \ =sum _{a_1=1}^msum _{a_2=1}^m...sum _{a_n=1}^m epsilon(gcd(a_1,a_2...a_n,m)) \ =sum _{a_1=1}^msum _{a_2=1}^m...sum _{a_n=1}^m sum _{d|a_i,d|m} mu(d) \ =sum _{d|m} mu(d)cdot (frac{m}{d})^n ]

复杂度(O(sqrt{m}logn))

注意这里实现,如果暴力求出莫比乌斯函数,再枚举(m) 的因子复杂度会达到(O(m))

所以求这个表达式的时候考虑莫比乌斯函数的性质,只需要考虑其中的质因子,然后(dfs) 一下质因子的贡献,复杂度就降到了(O(2^{f(m)})) ,其中(f) 表示质因子的个数

代码

int cnt;
ll res;
int n, m;
int pri[20];

void dfs(int cur, int p, int mu) {
    if (cur == cnt) {
        res += mu * ksm(m / p, n);
        return;
    }
    dfs(cur + 1, p, mu);
    dfs(cur + 1, p * pri[cur], -mu);
}


int main() {
    n = readint();
    m = readint();
    int k = m;
    for (int i = 2; i * i <= m; i++) {
        if (k % i == 0) {
            pri[cnt++] = i;
            while (k % i == 0) k /= i;
        }
    }
    if (k != 1) pri[cnt++] = k;
    dfs(0, 1, 1);
    Put(res);
}
原文地址:https://www.cnblogs.com/hznumqf/p/13589954.html