《信息安全数学基础一》第一章笔记

《信息安全数学基础一》第一章笔记

整除

  • 定义
    在整数域内,若 \(a = q\cdot b\) ,则 \(b\) 整除 \(a\) ,记作 \(a | b\)
  • 性质
    • \(a | b,\ b | c\) ,则 \(a | c\)
    • \(c | a_{i},\ i = 1,\ 2,\ ..,\ n\)\(c\) 也整除 \(a_{i}\) 的线性组合

素数,合数

  • 素数定义
    除了 \(1\) 和自身外,没有因数的数,称之为素数,也称为质数,其他数被称为合数。
  • \(2\) 是最小的素数

素数判别

  • 一个定理
    对于合数 \(n\) ,必然存在不超过 \(\sqrt{n}\) 的质因子。

    \(n = pq\),设 \(p\) 是最小因子,则 \(p\leq q\)
    \(n = pq \geq p^{2}\)
    所以 \(p\leq \sqrt{n}\)
    假设 \(p\) 是合数,则可以继续进行分解,与题设不符,所以 \(p\) 是质数。

  • 定理推论
    对于一个数 \(n\) ,若其不存在不超过 \(\sqrt{n}\) 的质因子,那么其为素数。
  • 素数平凡判别
    枚举 \(2-\sqrt{n}\) 内的素数,若不存在 \(n\) 的因子,那么 \(n\) 是素数,否则是合数。

筛法

筛法用来求 \(2-n\) 内的所有素数。

埃式筛

  • 算法思想
    先假设所有数均为素数。
    对于数 \(x\) ,若其为素数,则筛去其所有倍数,并标记该值为合数;若其为合数,则不做改动。

  • 算法优化

    • 对于素数 \(x\) ,从 \(x\) 倍开始枚举。因为对于倍数 \(x * y,\ y < x\) ,已经在判断 \(y\) 时筛去了。
      例如 \(35 = 5 * 7\) ,在判断素数 \(5\) 时筛去了一次,在判断素数 \(7\) 时就可以直接从 \(49 = 7 * 7\) 开始筛。
    • \(n\) 以内的素数判断到 \(\sqrt{n}\) 即可。
  • 时间复杂度为 \(O(nlglgn)\)

  • \(code\)

    int n, vis[N];
    void getPrime()
    {
        for(int i = 2; i <= n; ++i) vis[i] = 1;
        for(int i = 2; i * i <= n; ++i){
            if(vis[i]){
                for(int j = i * i; j <= n; j += i)
                    vis[j] = 0;
            }
        }
    }
    

欧拉筛

  • 埃式筛的困境及改善
    有些合数会被筛去多次,例如 \(63 = 7 * 9 = 3 * 21\)

  • 优化
    让每个合数只被其最小的质因子筛去一遍,就可以控制复杂度到 \(O(n)\)

  • 细节

    • 先默认所有数都是素数,下面考虑内循环。
    • 若当前数是素数,将其所有的素数倍全部筛去,这保证了那些合数是被其最小素因子筛去的。
    • 若当前数是合数,筛去其素数倍 \(x\) ,若 \(x\) 能整除当前合数,则退出循环,因为继续循环得到的新倍数完全可以在之后被 \(x\) 整除。
  • \(code\)

    int n, prime[N], vis[N];
    int Euler_sieve()
    {
        int cnt = 0;//length of prime table
        for(int i = 2; i <= n; ++i)
            vis[i] = 1;
        for(int i = 2; i <= n; ++i){
            if(vis[i]) prime[++cnt] = i;
            for(int j = 1; j <= cnt && prime[j] * i <= n; ++j){
                vis[prime[j] * i] = 0;
                if(i % prime[j] == 0) break;
            }
        }
        return cnt;
    }
    

进制转换

考虑 \(k\) 进制,则一个数位 \(digit\) 的取值范围为 \([0,\ k)\)

  • 向十进制转换
    对于一个 \(n\)\(k\) 进制数,化为十进制数即为

\[\sum_{i = 0}^{n - 1}a_{i}k^{i} = a_{n - 1}k^{n - 1} + a_{n - 2}k^{n - 2} +\ ...\ +a_{0} \]

  • 十进制数转为 \(k\) 进制
    先模 \(k\) 得到低位在 \(k\) 进制下的值,然后除 \(k\) 舍去低位。

    //k 进制的字符串向十进制转换
    int num = 0;
    for(int i = 0; i < s.length(); ++i)
        num *= 10, num += s[i] - '0';
    
    //十进制转换为 k 进制
    stack<int> sta;
    while(num) {
        sta.push(num % k);
        num /= k;
    }
    while(!sta.empty())
        cout<<sta.top()<<endl, sta.pop();
    

最大公因数与最小公倍数

  • 二者定义
    字如其名。前者是最大的公因数,后者是最小的公倍数。

  • 关系

    \[[a,\ b] = \frac{ab}{(a,\ b)} \]

    \[[a_{0},\ a_{1},\ ...\ ,a_{n}] = \frac{\prod_{i = 0}^{n}a_{i}}{(a_{0},\ a_{1},\ ...\ ,a_{n})} \]

    通过证明 \((\frac{a}{(a,\ b)},\ \frac{b}{(a,\ b)}) = 1\) ,以及 \((a,\ b) = 1,\ [a,\ b] = ab\) 可以证明上式。

欧几里得算法

欧几里得算法即为辗转相除法计算最大公因数。

  • 定理 \(1\)
    \(a = q\cdot b + c\) 中,\((a,\ b) = (b,\ c)\)

    \((a,\ b) = d_{1},\ (b,\ c) = d_{2}\)
    \(d_{1}|a,\ d_{1}|b,\ d_{1}|c\) ,所以 \(d_{1}\leq d_{2}\)
    同理 \(d_{2}|b,\ d_{2}|c,\ d_{2}|a\) ,所以 \(d_{2}\leq d_{1}\)
    所以 \(d_{1} = d_{2}\)

  • 定理 \(2\)
    \((a,\ 0) = a\)

    \(a\)\(a\) 的最大因数,\(a\)\(0\) 的因数,所以 \((a,\ 0) = a\)

  • 欧几里得算法
    \(r_{0} = a,\ r_{1} = b,\ r_{n + 1} = 0\), 则有下列式子

    \[r_{0} = r_{1}q_{1} + r_{2} \\r_{1} = r_{2}q_{2} + r_{3} \\... \\r_{i - 1} = r_{i}q_{i} + r_{i + 1} \\... \\r_{n - 1} = r_{n}q_{n} + r_{n + 1} \]

    依据定理 \(1\) 和定理 \(2\) ,辗转相除便可以得到最大公因数

贝祖等式

  • \(s\cdot a + t\cdot b = (a,\ b)\)
  • 猜想 \(r_{i} = s_{i}a + t_{i}b,\ i\in [0,\ n]\) ,利用数学归纳法可以证明此猜想。

拓展欧几里得算法

\((a,\ b)\) 的同时求出 \(s\cdot a + t\cdot b = (a,\ b)\) 的一个特解 \(s_{0},\ t_{0}\)

  • 递推式算法
    考虑已经由数学归纳法证明猜想

    \[r_{i} = s_{i}a + t_{i}b,\ i\in [0,\ n] \]

    联立

    \[r_{i} = r_{i - 2} - q_{i - 1}r_{i - 1} \]

    得到递推式

    \[s_{i} = s_{i - 2} - s_{i - 1}q_{i - 1} \]

    \[t_{i} = t_{i - 2} - t_{i - 1}q_{i - 1} \]

    其中, \(i\)\(2\) 开始计数,即 \(i\in [2,\ n]\)

    \[q_{i} = \left [\frac{r_{i - 1}}{r_{i}}\right ] \]

    \[r_{i} = r_{i - 1}\ mod\ r_{i} = r_{i - 1} - q_{i}r_{i} \]

    其中, \(i\)\(1\) 开始计数,即 \(i\in [1,\ n - 1]\)

    考虑初值,易得

    \[s_{0} = 1,\ s_{1} = 0 \]

    \[t_{0} = 0,\ t_{1} = 1 \]

    \[r_{0} = a,\ r_{1} = b \]

    \[q_{1} = \left[\frac{a}{b}\right] \]

    如此一路递推,便可以得到最终的特解。

    考虑空间优化,可以只用 \(s_{0},\ s_{1},\ t_{0},\ t_{1},\ r_{0},\ r_{1},\ q_{0}\) 几个变量来进行递推,赋值的时候需要再引入中间变量来保存值,最终的空间复杂度为一个常数。

    int s0, s1, s2, t0, t1, t2, r0, r1, r2, q1, cnt;
    pair<int, int> exgcd(int a, int b)
    {
        s0 = 1, s1 = 0, t0 = 0, t1 = 1;
        r0 = b, r1 = a % b, q1 = a / b;
        while(r1) {
            s2 = s1, s1 = s0 - s1 * q1, s0 = s2;
            t2 = t1, t1 = t0 - t1 * q1, t0 = t2;
            q1 = r0 / r1;
            r2 = r1, r1 = r0 - q1 * r1, r0 = r2;
        }
        return pair<int, int> {s1, t1};
    }
    
  • 递归算法
    考虑递归终点,有 \(b = 0,\ (a,\ b) = a\) ,所以 \(s = 1, t = 0\)
    考虑已经求出了 \((b,\ a \% b)\) 情况下的 \(x',\ y'\) ,回溯求解 \((a,\ b)\) 下的 \(x,\ y\)

    \[bx'+ (a - \left \lfloor \frac{a}{b}\right \rfloor b)y' = ax + by \]

    解出

    \[x = y',\ y = x' - \left \lfloor \frac{a}{b}\right \rfloor y' \]

    如此一路回溯,可以得到一组特解 \(x_{0},\ y_{0}\)

  • \(code\)

    int exgcd(int a, int b, int &x, int &y)
    {
        if(!b) {x = 1, y = 0; return a;}
        int r = exgcd(b, a % b, y, x);//y的值被修改为x',x的值被修改为y'
        y -= (a / b) * x;
        return r;
    }
    

算术基本定理

  • 算术基本定理
    对于任意大于 \(1\) 的整数 \(n\) ,其可以拆分为质因子幂的乘积的形式,称之为 \(n\) 的标准分解式:

    \[n = \prod_{i = 1}^{k}p_{i}^{\alpha_{i}} \]

    其中, \(p_{i}\) 是素数。
  • 因数个数
    由乘法原理知道, \(n\) 的因数的个数为

    \[n = \prod_{i = 1}^{k}(1 + \alpha_{i}) \]

猜你喜欢

转载自www.cnblogs.com/ChenyangXu/p/12571937.html