zoukankan      html  css  js  c++  java
  • 约数相关

    约数

    约数简介

    定义

    若整数 n 除以整数 d 的余数为 0,即 d 能整除 n, 则称 d 是 n,的约数,n 是 d 的倍数,记为 d|n

    在算术基本定理中 (N)可被分解成下面这个样子

    [N=prod_{i=1}^m p_i^ {c_i}, p_1<p_2<…<p_m , c_i ∈ N^* ]

    那么(N)的正约数个数为:

    [(c_i+1)*(c_i+2)*…(c_m+1)=prod_{i=1}^{m}(c^i+1) ]

    (N)的所有正约数和为:

    [prod_{i=1}^{m}{(sum_{j=0}^{c^i}(p_i)^j)} ]

    求解(N)的正约数集合

    • 试除法

    $ qquad $ 如果一个数(x)(N)的约数,那么(N/d≤sqrt N)也为(N)的约数。

    $ qquad $ 因为约数总是成对出现,因此扫描 (x=1-sqrt N ∈Z),尝试是否 (x|N)。但是我们要特判完全平方数,因为对于完全平方数(sqrt N ∈Z)

        int factor[1600], num = 0;
        for(int i = 1; i * i <= n; i++) {
            if(n % i == 0) {
                factor[++num] = i;
                if(i != n/i) 
                    factor[++num] = n / i;
            }
        } 
    

    $ qquad $ 求(1-sqrt N)每个数的正约数集合——倍数法

    基本思想:

    不同于试除法,我们可以反过来考虑每个数(x),则以(x)为约数的数就是(x,2x,3x…)

        vector<int> factor[SIZE];
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n / i; j++)
                factor[i*j].push_back(i);		
        //输出
        for(int i = 1; i <= n ;i++) {
            for(int j = 0; j < factor[i].size; j++)
                printf("%d ",factor[i][j]);
            putchar('
    '); 
        }
    


    $ qquad $ 在小数据内((N∈[4,16])),试除法是要快于倍数法的,复杂度为(O(Nsqrt N))

    约数相关内容:

    1.最大公约数|(gcd)

    • 定义

    若自然数(x)满足 (x|a)(x|b),则称(x)(a)(b)的公约数,则(max(x))就是(a)(b)的最大公约数,记为(gcd(a,b))
    同理,若同时满足(a|x)(b|x),则(x)(a)(b)的公倍数,在这样的(x)中最小的一个,为(a,b)的最小公倍数,记为(lcm(a,b))

    定理:

    [∀a,b∈N, qquad qquad gcd(a,b)*lcm(a,b)=a*b ]

    以上定义的证明读者可以自行尝试,也可以《参考算法竞赛进阶指南》

    • 求解方法

    浅谈质因数分解中我们已经提到了求解(gcd)的算法:1.更相减损术 2.辗转相除法。

    《九章算术》有:

    [∀a,b∈N,a≥b,quad gcd(a,b)=gcd(b,a-b)=gcd(a,a-b) ]

    [∀a,b∈N,quad gcd(2a,2b)=2gcd(a,b) ]

    以上两条定理很重要,这涉及我们后面的二进制优化(gcd)

    欧几里得算法:

    [∀a,b∈N,b≠0,qquad gcd(a,b)=gcd(b,a quad mod quad b) ]

    这样就得出了我们熟悉的辗转相除法

        //递归形式
        int gcd(int a, int b) {
            return b ? gcd(b, a % b) : a;
        } 
    
        //非递归形式
        int gcd(int a, int b) {
            int temp;
            while(b) {
                temp=a % b;
                a = b;
                b = temp;
            }	
            return a;
        } 
    

    $ qquad qquad (欧几里得算法时间复杂度为)O(log(a+b))$。对于高精度算法,取模不容易实现,建议使用更相减损术代替。

    $ qquad qquad (当然,)gcd$还可以优化(就是前面提到的二进制优化)。

    • 为什么可以优化?因为辗转相除法运用了模运算,这样常数大运行慢,故用更相减损+二进制优化(gcd)
    1. (a=0, quad return quad b; quad mid quad b=0, quad return quad a;)

    2. (a<b,a quad xor= quad b, quad b quad xor= quad a, quad a quad xor= quad b;)(独特的二进制交换)

    3. (a) & (1)(b) & (1),$ quad ans=2gcd(a >> 1,b>>1);$

    4. (a) & (1) 且 !(b) & (1),$ quad ans=gcd(a >> 1,b);$

    5. (a) & (1)(b) & (1),$ quad ans=gcd(a,b >> 1);$

    6. (a) & (1) 且 !(b) & (1),$ quad ans=gcd(a - b,b)$。

        //下面代码返回gcd(a,b)的值同时把b赋予这个值,不需要可以把&去掉
        int gcd(int a,int &b) {
            if(a == 0 || b == 0) return b = a + b; 
            int n = 0, m = 0;
            for(; !(a & 1); a >>= 1, n++); 
            for(; !(b & 1); b >>= 1, m++);
            n = m < n ? m : n;
            while(a) {
                if(a < b) { a ^= b, b ^= a, a ^= b;}
                if(!(a -= b)) return b <<= n;
                while(!(a & 1)) a >>= 1;
            }
        }
    

    但注意上面代码在负数的时候是错误的,因为负数的右移(1)位和除(2)出不一样的,所以遇到负数时上面的位运算要用正常除法代替。

    2.互质与欧拉函数

    • 定义:

    (∀a,b∈N),若(gcd(a,b)=1),则称(a,b)互质。

    对于三个数及以上的情况类比即可,这里不再赘述,读者可以自行查阅相关资料。

    欧拉函数

    $ qquad $ (1-N)中与(N)互质的个数被称为欧拉函数,记为(φ(N))

    在算数基本定理中,(N=prod_{i=1}^m p_i^ {c_i}),则:

    [φ(N)=N*frac{1-p_1}{p_1}*frac{1-p_2}{p_2}*frac{1-p_3}{p_3}*…*frac{1-p_m}{p_m}=N*prod_{prime p|N}(1-frac{1}{p}) ]

    根据欧拉函数的计算式,我们只需要分解质因数,即可求出欧拉函数:

        //参考代码(源于《算法竞赛进阶指南》) 
        int phi(int n) {
            int ans = n;
            for(int i = 2; i <= sqrt(n); i++) 
                if(n % i == 0) {
                    ans = ans / i * (i - 1);
                    while(n % i == 0) n /= i;
                }
            if(n > 1) ans = ans / n * (n - 1);
            return ans;
        }
    
    • 欧拉函数的性质:
    1. (∀n>1,1-n)中与(n)互质的数和为(n*φ(n)/2)

    2. (gcd(a,b)=1),即(a,b)互质,则(φ(ab)=φ(a)φ(b))

    3. (p)为质数,若 (p mid n)(p^2 mid n),则(φ(n)=φ(n/p)*p)

    4. (p)为质数,若 (p mid n)(p^2 mid n),则(φ(n)=φ(n/p)*(p-1))

    5. (sum_{d mid n}φ(d)=n)

    积性函数:

    $ qquad $ 如果(gcd(a,b)=1),有(f(ab)=f(a)f(b)),那么称函数(f)为积性函数

    1. (f)是积性函数,且在算术基本定理中(n=prod_{i=1}^m p_i^ {c_i}),则$ f(n)=prod_{i=1}^m f(p_i^ {c_i})$。

    (第六点同为欧拉函数的性质)

    (*)完全积性函数:

    [∀a,b∈Z, qquad f(ab)=f(a)f(b) ]

    关于积性函数的拓展非常多,内容也比较深奥,下面简单介绍下:

    常用积性函数如下

    1. (φ(n)) —— 欧拉函数

    2. (σ(n)) —— 约数和函数

    3. (μ(n)) —— 莫比乌斯函数

    4. (σ_0(n)) —— 约数个数函数

    5. (σ_k(n)) —— 约数次数和函数

    6. (gcd(n,k)) —— 最大公约数函数,当(k)固定时

    7. (1(n)=1) ——这个我也不知道是什么

    8. (f(n)=n)——我还是不知道是什么

    $ qquad $还有一点,就是积性函数都是可以线性筛的

    • 狄利克雷卷积

    首先先补充下数论函数的定义:

    1. 陪域:包含值域的任意集合

    2. 数论函数:定义域为正整数,陪域为复数的函数

    好了,我们可以开始介绍狄利克雷卷积了。

    定义(f,g)为数论函数,则它们的狄利克雷卷积可以表示为(f*g),设(h=f*g)

    [h(n)=sum _{d|n}f(d)gBig(frac{n}{d}Big) ]

    (f,g)是积性函数,显然,(h)也是积性函数。

    证明

    $ qquad $ 设(n = a*b)(a,b)互质,即(gcd(a,b)=1)

    [h(n)=sum _{d_1|a, d_2|b}f(d_1d_2)gBig(frac{a}{d_1}frac{b}{d_2}Big) ]

    [=sum_{d_1|a, d_2|b}f(d_1)f(d_2)gBig(frac{a}{d_1}Big)gBig(frac{b}{d_2}Big) ]

    [=sum_{d_1|a}f(d_1)gBig(frac{a}{d_1}Big)sum_{d_2|b}f(d_2)gBig(frac{b}{d_2}Big) ]

    [=h(a)*h(b) ]

    $ qquad $证毕。

    运算法则

    狄利克雷卷积的运算满足:

    1. (f*g=g*f)(交换律)

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

    3. (f*(g+h)=f*g+f*h)(分配律)

    4. (f,g)是积性函数,则(f*g)也是积性函数。(性质)

    狄利克雷卷积相关


    下面还是回到欧拉函数:

    $ qquad $ 我们可以利用 (Eratosthenes) 筛法,按照欧拉函数的计算式,在(O(NlogN))时间内求解出 (2-N)中每个数的欧拉函数。

        int phi[SIZE];
        void eluer(int n) {
            for(int i = 2; i <= n; i++) phi[i] = i;
            for(int i = 2; i <= n; i++) 
              if(phi[i] == i) 
                  for(int j = i; j <= n; j += i;) 
                    phi[j] = phi[j] / i * (i - 1);
        }
    

    $ qquad $ 但是既然说了积性函数都是可以线性筛的,那么欧拉函数如何优化成线性的呢?让我们来回顾质数线性筛的思想(质数筛法详解),线性筛中,每个合数(n)只会被它的质因子筛一次,利用下面几条性质:

    1. 定理三:设 (p) 为质数,若 $p mid n (且) p^2 mid n(,则)φ(n)=φ(n/p)*p$。

    2. 定理四:设 (p) 为质数,若 $p mid n (且) p^2 mid n(,则)φ(n)=φ(n/p)*(p-1)$

    我们就可以在筛选合数时运用这两条定理,从(φ(n/p))递推到(φ(n))

    关于质数筛法,因为有两种线性筛的写法,其实是大同小异的,但是为了读者方便,这里都给出:

        //法一 : 
        int v[SIZE], pri[SIZE], phi[SIZE], num;
        void promoted_eluer(int n) {
            for(int i = 2; i <= n; i++) {
                if(v[i] == 0) 
                    pri[++num] = i, phi[i] = i - 1;
                for(int j = 1; j <= num && i * pri[j] <=n; j++) {
                    v[i * pri[j]] = 1;
                    phi[i * pri[j]]=
                      phi[i] * (i % pri[j] ? pri[j] - 1 : pri[j]);
                    if(i % pri[j] == 0) break;
                }
            }
        }
    
        //法二: 
        int v[SIZE], pri[SIZE], phi[SIZE], num;
        void promoted_eluer(int n) {
            for(int i = 2; i <= n; i++) {
                if(v[i] == 0) 
                    pri[++num] = i, phi[i] = i - 1, v[i] = i;
                for(int j = 1; j <= num; j++) {
                    if(pri[j] > v[i] || pri[j] > n / i) break;
                    v[i * pri[j]] = pri[j];
                    phi[i * pri[j]]=
                      phi[i] * (i % pri[j] ? pri[j] - 1 : pri[j]);
                }
            }
        }
    

    ※章末练习

    1. P1029 最大公约数和最小公倍数问题

    2. P2205 [USACO13JAN]画栅栏Painting the Fence

    3. UVA12716 GCD等于XOR GCD XOR

    4. P2303 [SDOi2012]Longge的问题

    5. UVA10791 最小公倍数的最小和 Minimum Sum LCM

    6. P1072 Hankson 的趣味题

    7. P2261 [CQOI2007]余数求和

    8. P2520 [HAOI2011]向量

    9. P2152 [SDOI2009]SuperGCD

    10. P1463 [POI2002][HAOI2007]反素数

    11. P2455 [SDOI2006]线性方程组

    12. P3213 [HNOI2011]勾股定理

    13. P3327 [SDOI2015]约数个数和

    14. P3166 [CQOI2014]数三角形

    15. P2500 [SDOI2012]集合

    16. P2086 [NOI2012]魔幻棋盘

    17. P3307 [SDOI2013]项链


    (END)

    (PS:)

    以上讲解顺序及内容参考:李煜东《算法竞赛进阶指南》

  • 相关阅读:
    python文本处理
    转 Deep Learning for NLP 文章列举
    backpropagation
    开发者必备的6款源码搜索引擎 转
    转【面向代码】学习 Deep Learning(二)Deep Belief Nets(DBNs)
    Sampling
    各种形式的熵函数,KL距离
    [转] 如何在ie11里使用a连接创建动态下载文件流
    修改chrome背景色
    [转] 使用 Spring 5 的 WebFlux 开发反应式 Web 应用
  • 原文地址:https://www.cnblogs.com/Ning-H/p/11567272.html
Copyright © 2011-2022 走看看