数论基础

基础数论

原根

​ 定义:a % m 的阶 = $ \Phi(m)$,a叫m的原根。(我吐了)

​ 定义:\(a^0,a^1,a^2...a^{\phi(m) - 1}\pmod m\),这些数两两不同,则a是\(\pmod m\)意义下的原根。

​ 性质:1.原根一般比较小,大概是小于10或者十几的数吧。

​ 2.一个正整数\(m\)\(m\)有原根当且仅当\(m=2,4,p^a,2*p^a\)\(p\)为奇素数。

​ 那咋求一个数的原根呢?

​ 1.保利写法:

int get_yuan_gen(int p) {
    int phip = phi(p);
    for(int a = 2; ; a++) {
        int x = 1, flag = 1;
        for(int i = 0;i < phip; i++) {
            z[i] = x;
            x = 1ll * x * a % p;
        }
        sort(z, z + phip);
        for(int i = 1;i < phip; i++) {
            if(z[i] == z[i - 1]) { flag = 0; break; }
        }
        if(flag) return a;
    }
}

​ 可以看出这个代码复杂度是\(O(k\phi(p))\)的,不太妙。

​ 2.优化写法:

int get_yuan_gen(int p) {
    int phip = phi(p);
    for(int a = 2; ; a++) {
        int flag = 1;
        for(int i = 0;i * i <= phip && flag; i++) {
            if(phip % i == 0) {
                if(ksm(a, i, phip) == 1) flag = 0;
                if(ksm(a, phip / i, phip) == 1) flag = 0;
            }
        }
        if(flag) return a;
    }
}

​ 时间复杂度是\(O(k\sqrt{\phi(p)} )\),挺妙的。

​ 为啥这么写,证明:

​ 当前枚举到的数\(g\)如果不是原根,那么必定有:\(g^a \equiv g^b \pmod{p}\)

​ 化简一下得:\(g^{a - b} \equiv 1 \pmod{p}\)

​ 根据欧拉定理我们知道:\(g^{\phi(p)} \equiv 1 \pmod{p}\)

​ 所以:\(a - b | \phi(p)\)。我们只需找一个\(\phi(p)\)的约数\(k\),然后判断是否\(g^k \equiv 1 \pmod {p}\)就可以了。

Miller_Rabin素性测试

​ 如何快速判断一个\(10^{18}\)大小的数是否是素数,如果采用\(O(\sqrt n)\)可能很悬,这时候就要用到Miller_Rabin来判断素数了。

​ 令\(n = 2 ^r +d - 1\),取\(0\le a < n\),若\(n\)为素数,则一定满足以下两个条件其中之一:

​ 1.\(a^d \equiv 1 \pmod{n}\)

​ 2.存在\(0 \le i < r\),使\(a ^ {d * 2 ^ i} \equiv n - 1\pmod{n}\)

证明:费马小定理。

​ 如果一个数满足这两个条件,那么它可能是素数。我们现在多枚举几个\(a\),让\(n\)多经过几次测试,每次通过测试的概率可以认为是\(\frac{1}{2}\)(事实上比\(\frac{1}{2}\)还要大),十次测试过后,这个数是素数的概率变为了\(\frac{1023}{1024}\),接近于一,可以说非常大了。(一个大佬说好像long long范围内的数都不会被卡)

bool miller_rabin(int n, int a) {
    int d = n - 1, r = 0;
    while(d % 2 == 0) d /= 2, r++;
    int x = ksm(a, d, n);  
    if(x == 1) return 1;
    for(int i = 0;i < r; i++) {
        if(x == n - 1) return 1;
        x = 1ll * x * x % n; //a^d, a^2d, a^4d, a^8d...
    }
    return 0;
}

int prime[10] = {0, 2, 3, 5, 7, 11, 23, 37, 47};

bool is_prime(int n) {
    for(int i = 1;i <= 8; i++) {
        if(!miller_rabin(n, prime[i])) return 0;
    }
    return 1;
}

​ 复杂度\(O(klogn)\)。很妙。

狄利克雷卷积

​ 定义:\((f*g)(n) = \displaystyle \sum_{d|n} f(d) * g(\frac{n}{d})\)

​ 性质:1.交换律:\(f*g = g * f\)

​ 2.结合律:\((f*g)*h = f * (g * h)\)

​ 3.分配率:\((f + g) * h = f * h + g * h\)

​ (有了这些性质可以把它理解为函数的乘法操作)

​ 重要等式:1.\(\mu * I = \epsilon\) $ (\epsilon(n) = [n = 1], I(n) = 1)$

​ 2.\(\phi * I = id\) \(id(n) = n\)

​ 3.\(\mu * id = \phi\)

​ 重要等式证明:

​ 1.\(\mu * I = \epsilon\)

\[(\mu * I)(n) = \displaystyle \sum_{d|n} \mu(d) * I(\frac{n}{d}) = \displaystyle \sum_{d|n} \mu(d) \\ n = 1 : \displaystyle \sum_{d|n} \mu(d) = \mu(1) = 1 = \epsilon(1) \\ n \ne 1: n = p_1^{k_1}p_2^{k_2}...p_r^{k_r},d = p_1^{a_1}p_2^{a_2}...p_r^{a_r} (0 \le a_i \le k_i) \\ \because a_i = 0, 1时,\mu(d) \ne 0 \therefore d有2^r种选法 \\ 可以发现\mu(d) = 1的个数等于\mu(d) = -1的个数 \\ \therefore \displaystyle \sum_{d|n} \mu(d) = 0 \\ \therefore \mu * I = \epsilon \]

​ 2.\(\phi *I = id\) 这个其实举例子就可以了,严谨的证明我不太会

\[设n = p_1^{k_1} \\ (\phi * I)(n) = \displaystyle \sum_{d|n} \phi(d) = \phi(1) + \phi(p_1) + \phi(p_1^2) + ...+\phi(p_1^{k_1}) = 1 + (p_1 - 1) + p_1 * (p_1 - 1) + .. + p_1^{k_1 - 1} * (p_1 - 1) \\ 把(p_1 - 1)提出来,发现有个等比数列 \\ (\phi * I)(n) = 1 + (p_1 - 1) * \frac{(1 - p_1 ^ {k_1})}{1 - p_1} = 1 + p_1^{k_1} - 1 = n = id(n) \\ \therefore \phi * I = id \]

​ 数学上有一个方法叫数学归纳法,把\(n\)的逐渐一般化,过程太复杂了(我吐了)

​ 3.\(\mu * id = \phi\) 这个把等式1,2带进去就好了

莫比乌斯反演

​ 如果\(g(n) = \displaystyle \sum_{d|n} f(d)\),则\(f(n) = \displaystyle \sum_{d|n} \mu(d) * g(\frac{n}{d})\)

​ 那样不好看,这样才好看:\(g = f * I \Leftrightarrow f = \mu * g\)。这个过程就叫反演。

\(\mu * g = \mu * f * I = \mu * I * f = \epsilon * f = f\)。(\(\epsilon\)卷上任何函数都是它本身)

​ 变换手段:1.增加枚举量。 2.交换枚举顺序。

原文地址:https://www.cnblogs.com/czhui666/p/13553534.html