BZOJ 2721 樱花 【推导 + 约数个数定理 + 阶乘含素因子定理】

传送门

题意: 1/x + 1/y = 1/n! 求这个等式的正整数解(x, y) 有多少对.

思路: 我们首先令n! = z, 那么原式就等于 1/x + 1/y = 1/z, 化简的 xz + yz = xy –> xz + yz - xy + z^2 = z^2,
就等于 (z-x)(z-y) = z^2, 很明显这个方程的解就是z^2的约数个数, 比如n = 2时, 就变成了4 = (2-x)(2-y), 变换一下就为4 = (x-2)(y-2), 很明显4有3个约数1, 2, 4, 所以我们每个相对应的带入进去解出x, y即可, 比如代入1时, x = 3, y = 6, 依次进行就是, 现在就是如何求(n!)^2的约数个数了? 首先 一个数的平方的约数个数很好求, 通过约数个数定理推导可知为(k*cnt1+1)*(k*cnt2+1)….., cnt1, 2分别时这个数的素数因子的个数, 那么问题就变成了如何快速的求n!的一些素数因子的个数,

定理: n!中含有素数p的个数为 [n/p] + [n/p^2] + …. + [n/p^k]

当然我们方便的求也可以反向求就一直用n/=p即可, 到此可解决此问题.

AC Code

const int maxn = 1e6+5;
int pri[maxn]; bool ispri[maxn];
void init(int n) {
    int k = 0; Fill(ispri, true); ispri[1] = false;
    for (int i = 2 ; i <= n ; i ++) {
        if (ispri[i]) {
            pri[++k] = i;
            for (int j = i+i ; j <= n ; j += i)
                ispri[j] = false;
        }
    }
    pri[0] = k;
}
int cal(int n, int m) {
    int res = 0;
    while(n) res += n /= m;
    return res;
}
void solve() {
    int n; scanf("%d", &n);
    ll ans = 1; init(n);
    for (int i = 1 ; i <= pri[0] && pri[i] <= n ; i ++) {
        (ans *= (2*cal(n, pri[i])+1)) %= mod;
    }
    printf("%lld\n", ans);
}

你可能感兴趣的:(数的因子(约数),素数相关)