威尔逊定理

一、威尔逊定理

1、定义:对于所有的素数都有:\((p-1)! \ \equiv \ (-1) \ (mod \ p) \ \equiv \ (p-1) \ (mod \ p)\)

2、应用:

我们令 \(f(n,p)=(n!)_{p}\) 为所有小于等于 \(n\) 但不能被 \(p\) 整除的正整数额乘积,即 \((n!)_{p}=n!/(\left \lfloor n/p \right \rfloor !p^{\left \lfloor n/p \right \rfloor })\)

举个例子:\((7!)_{3}=1·2·\underbrace{1}_{1*3} ·4·5·\underbrace{2}_{2*3}·7 \equiv 2 \ (mod \ 3)\)

然后我们可以发现一个每次需要计算的是 \((\left \lfloor \frac{n}{p} \right \rfloor !)_{p}+fac[n\%p]\) ,一直递归到 \(n \le 1\) 时就得到答案了,如果我们预处理下 \(fac[p-1]\),那么我们就能做到 \(O(log_{p}n)\) 的时间复习度。

struct Fact{
    int N;
    vector<i64> fac;
    Fact() {}
    Fact(int N_, i64 p = 1e9 + 7) : fac(N_ + 1) {
        N = N_;
        fac[0] = 1;
        for (i64 i = 1; i < p; i++) fac[i] = fac[i - 1] * i % p;
    }
    
    inline i64 get_fact(i64 n, i64 p) {
        i64 res = 1;
        while (n > 1) {
            if ((n / p) % 2) res = p - res;
            res = res * fac[n % p] % p;
            n /= p;
        }
        return res;
    }
};

二、\(Legendre\) 定理:时间复杂度为 \(log_{p}n\)

1、用途:可以求出某个模数 \(p\)\(n!\) 中所出现的幂次数。

2、我们令 \(v_p(n!)\) 表示 \(n!\) 的阶乘的所有素因子分解中 \(p\) 出现的次数,很明显我们能根据容斥得到如下式子,即 \(v_p(n!)=\sum_{i=1}^{p_i \le n}\left \lfloor \frac{n}{p_i} \right \rfloor=\frac{n-S_{p}(n)}{p-1}\)

3、其中 \(S_{p}(n)\) 表示 \(n\)\(p\) 进制下 \(n\) 的各个数位的和。

4、特别的当 \(p=2\) 时,式子为 \(v_{2}(n!)=n-S_{2}(n)\)

struct Legedre{
    inline i64 multi_fact(i64 n, i64 p) {
        i64 cnt = 0;
        do {
            n /= p;
            cnt += n;
        } while (n);
        return cnt;
    }
    
    inline i64 multi_fact2(i64 n, i64 p) {
        i64 cnt = 0;
        i64 m = n;
        while (n) {
            cnt += n % p;
            n /= p;
        }
        return (m - cnt) / (p - 1);
    }
};

三、\(Kummer\) 定理:时间复杂度为 \(log_{p}n\)

1、用途:可以求出某个模数 \(p\) 在组合数 \(C_{n}^{m}\) 中出现的幂次数,公式为:\(v_p(C_{n}^{m})=\frac{S_p(m)+S_{p}(n-m)-S_{p}(n)}{p-1}\)

struct Kummer{
    inline i64 multi_fact2(i64 n, i64 m, i64 p) {
        i64 cnt1 = 0, cnt2 = 0, cnt3 = 0;
       	i64 k = n - m;
        while (n) {
            cnt1 += n % p;
            n /= p;
        }
        while (m) {
            cnt2 += m % p;
            m /= p;
        }
        while (k) {
            cnt3 += k % p;
            k /= p;
        }
        return (cnt2 + cnt3 - cnt1) / (p - 1);
    }
};
posted @ 2024-08-31 17:03  grape_king  阅读(68)  评论(0)    收藏  举报