zoukankan      html  css  js  c++  java
  • 常用积性函数的线性筛法整理

    简单整理推导加代码,留复习用。


    线性筛素数

    最简单也最基础,直接看代码就好了(……)

    code:

    void Euler_Phi_Prime(int n) {
        is_prime[1] = true;
        for (int i = 2; i <= n; i++) {
            if (!is_prime[i]) prime[++cnt] = i;
            for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
                is_prime[i * prime[j]] = true;
                if (i % prime[j] == 0) break;
            }
        }
    }
    

    线性筛欧拉函数

    根据欧拉函数的两条性质(:)

    • (p)为素数,若(p|n)(p^2|n),则(varphi(n)=varphi(n/p)* p)

    • (p)为素数,若(p|n)(p^2 shortmid n),则(varphi(n)=varphi(n/p)* (p-1))

    对于第一条性质,若(p|n)(p^2|n),那么显然(n)(n/p)包含相同的质因子,并且将两者按照欧拉函数计算公式展开后只有(p)的指数不同,上下相除结果即为(p),故此性质成立。

    对于第二条性质,若(p|n)(p^2 shortmid n),说明(n)(n/p)互质,根据欧拉函数为积性函数,我们显然可以得到(varphi(n)=varphi(n/p) * varphi(p)),又因为(varphi(p)=p-1),所以显然成立。

    void Euler_Phi_Prime(int n) {
        phi[0] = phi[1] = 0;
        for (int i = 2; i <= n; i++) {
            if (!phi[i]) prime[++cnt] = i, phi[i] = i - 1;
            for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
                phi[i * prime[j]] = phi[i] * ((i % prime[j]) ? (prime[j] - 1) : prime[j]);
                if (i % prime[j] == 0) break;
            }
        }
    }
    

    线性求约数个数

    考虑我们根据算数基本定理得到的推论之一:

    一个正整数(N)的约数个数为:

    [d(N)=prod_{i=1}^{m}(1+c_i) ]

    在筛的过程中,我们记录(N)的最小素因子(st[N])

    我们根据筛素数分成三种情况考虑:

    (1.)当前的数(i)为素数的时候,显然它只有(1)和自己两个因子且只有自己一个素因子,此时(d(i)=2, st[i]=1)

    (2.)(i) % (prime[j]!=0)时,显然(i)不包含(prime[j])这个质因子,且(prime[j])一定是(i * prime[j])的最小质因子,因为我们是在从小到大枚举素数,这样(i * prime[j])就相当于比(i)多了一个因子(prime[j]),那么(i * prime[j])的约数和就为(:)

    [d(i * prime[j])=(1+c_1)(1+c_2)……(1+c_m)(1+1) ]

    最后的((1+1))即表示质因数分解后(prime[j])的指数为(1),此时(d(i * prime[j])=d(i) * d(prime[j])) (st[i * prime[j]]=1).

    (3.)(i)%(prime[j]==0)时,显然(i)是包含(prime[j])这个质因子的,(i * prime[j])只是比(i)多了一个(i)的最小质因子,(()因为是从小到大枚举素数的())(:)

    [(i * prime[j])=(1+c_1+1)(1+c_2)……(1+c_m) ]

    所以此时(d(i * prime[j])=d(i) / (st[i] + 1) * (st[i] + 2)) (st[i * prime[j]]=st[i]+1)

    code:

    void Euler_Phi_Prime(int n) {
        is_prime[1] = true, d[1] = 1;
        for (int i = 2; i <= n; i++) {
            if (!is_prime[i]) prime[++cnt] = i, d[i] = 2, st[i] = 1;
            for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
                is_prime[i * prime[j]] = true;
                if (i % prime[j] == 0) {
                    d[i * prime[j]] = d[i] / (st[i] + 1) * (st[i] + 2);
                    st[i * prime[j]] = st[i] + 1; break;
                }
                d[i * prime[j]] = d[i] * d[prime[j]], st[i * prime[j]] = 1;
            }
        }
    }
    

    线性筛约数和

    考虑算术基本定理的另一个推论(:)

    一个正整数(N)的约数和为(:)

    [sd(N)=prod_{i=1}^{m}{largelbrace}sum_{j=0}^{c_i}(p_i)^j{large brace} ]

    [sd(N)=(1+p_1+p_1^2+ ……+p_1^{c_1})(1+p_2+p_2^2+ ……+p_2^{c_2})……(1+p_m+p_m^2+ ……+p_m^{c_m})]

    筛的过程中我们记录(st[i]=(1+p_i+p_i^2+ ……+p_i^{c_i}))

    仍旧按筛素数的情况分成三种情况考虑(:)

    (1.)当当前的数(i)为质数时,显然(i)只有(1)和自己两个因子,显然(sd[i]=st[i]=i+1)

    (2.)(i)%(prime[j]!=0)时,显然(i)并不包含(prime[j])这个质因子,且(prime[j])一定是(i * prime[j])的最小质因子,因为我们是在从小到大枚举素数,这样(i * prime[j])就相当于比(i)多了一个因子(prime[j]),答案多累加上(prime[j])的贡献即可(:)

    [sd(i* prime[j])=(1+p_1+p_1^2+ ……+p_1^{c_1})……(1+p_m+p_m^2+ ……+p_m^{c_m})(1+prime[j])]

    此时,(sd[i* prime[j]]=sd[i] * sd[prime[j]], st[i* prime[j]]=prime[j]+1)

    (3.)(i)%(prime[j]==0)时,显然(i)是包含(prime[j])这个质因子的,(i * prime[j])只是比(i)多了一个(i)的最小质因子,(()因为是从小到大枚举素数的()),所以(i* prime[j])的约数和就表示为(:)

    [sd(i * prime[j])=(1+p_1+p_1^2+ ……+p_1^{c_1}+p_1^{c_1+1})……(1+p_m+p_m^2+ ……+p_m^{c_m})]

    此时,(sd[i * prime[j]]=sd[i] / st[i] * (st[i] * prime[j]+1), st[i * prime[j]]=st[i]* prime[j]+1)

    code:

    void Euler_Phi_Prime(int n) {
        is_prime[1] = true, sd[1] = 1;
        for (int i = 2; i <= n; i++) {
            if (!is_prime[i]) prime[++cnt] = i, sd[i] = i + 1, st[i] = i + 1;
            for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
                is_prime[i * prime[j]] = true;
                if (i % prime[j] == 0) {
                    sd[i * prime[j]] = sd[i] / st[i] * (st[i] * prime[j] + 1);
                    st[i * prime[j]] = st[i] * prime[j] + 1; break;
                }
                sd[i * prime[j]] = sd[i] * sd[prime[j]], st[i * prime[j]] = prime[j] + 1;
            }
        }
    }
    

    线性筛莫比乌斯函数

    窝太菜了,证明还是先鸽着吧(……)

    code:

    void Euler_phi(int n) {
    	is_prime[1] = true, mu[1] = 1;
    	for (int i = 2;  i <= n; i++) {
    		if (!is_prime[i])
    			prime[++cnt] = i, mu[i] = -1;
    		for (int j = 1; j <= cnt && (i * prime[j]) <= n; j++) {
    			is_prime[i * prime[j]] = true;
    			if (i % prime[j] == 0) {
    				mu[i * prime[j]] = 0;
    				break;
    			}
    			mu[i * prime[j]] = -mu[i];
    		}
    	}
    }
    
  • 相关阅读:
    【转】C++轻量级可配置语法分析器
    [转载]正则表达式大全
    Batch update returned unexpected row count from update 错误解决方法
    [转载]C# ToString格式字符串整理(Format)(数字、日期和枚举的标准格式设置说明符)(SamWang)
    Centos配置mono环境
    ASP.NET MVC 4 简介
    添加控制器 Adding a Controller
    [转载]OrmHate
    [转载]张小龙谈移动互联网产品
    [转载]Golden Ratio in logo designs
  • 原文地址:https://www.cnblogs.com/Hydrogen-Helium/p/11737268.html
Copyright © 2011-2022 走看看