zoukankan      html  css  js  c++  java
  • 数论基础

    基础数论

    原根

    ​ 定义: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.交换枚举顺序。

  • 相关阅读:
    12款有助于简化CSS3开发的工具
    log4net简介
    javascript面向对象重写右键菜单事件
    Winform 通用分页控件实战篇(提供源码下载)
    新浪微博信息站外同步的完整实现
    2003 IIS 发布WEB攻略
    FCKeditor.NET的配置、扩展与安全性经验交流
    js获取本地文件夹和文件 .
    前端必读:浏览器内部工作原理
    程序员第二定律:量化管理在程序员身上永无可能
  • 原文地址:https://www.cnblogs.com/czhui666/p/13553534.html
Copyright © 2011-2022 走看看