zoukankan      html  css  js  c++  java
  • 利用积性函数的优化(线性时间:筛素数、求1~n的欧拉函数、约数个数)

    这个文章主要介绍了3算法 1线性时间筛素数 2线性时间求前n个数的欧拉函数值 3线性时间求前n个数的约数个数   一、 首先介绍下积性函数。   下面是wiki的条目:   在非数论的领域,积性函数指有对于任何a,b都有性质f(ab)=f(a)f(b)的函数。   在数论中的积性函数。对于正整数n的一个算术函数f(n),当中f(1)=1且当a,b互质,f(ab)=f(a)f(b),在数论上就称它为积性函数。 若某算术函数f(n)符合f(1)=1,且就算a,b不互质,f(ab)=f(a)f(b),称它为完全积性的。   例子 φ(n) -欧拉φ函数,计算与n互质的正整数之数目 μ(n) -默比乌斯函数,关于非平方数的质因子数目 gcd(n,k) -最大公因子,当k固定的情况 d(n) -n的正因子数目 σ(n) -n的所有正因子之和 σk(n): 因子函数,n的所有正因子的k次幂之和,当中k可为任何复数。在特例中有: σ0(n) = d(n) 及 σ1(n) = σ(n) 1(n) -不变的函数,定义为 1(n)=1 (完全积性) Id(n) -单位函数,定义为 Id(n)=n (完全积性) Idk(n) -幂函数,对于任何复数、实数k,定义为Idk(n) = nk (完全积性) Id0(n) = 1(n) 及 Id1(n) = Id(n) ε(n) -定义为:若n = 1,ε(n)=1;若n > 1,ε(n)=0。有时称为“对于狄利克雷回旋的乘法单位”(完全积性) (n/p) -勒让德符号,p是固定质数(完全积性) λ(n) -刘维尔函数,关于能整除n的质因子的数目 γ(n),定义为γ(n)=(-1)ω(n),在此加性函数ω(n)是不同能整除n的质数的数目 所有狄利克雷特性均是完全积性的     二、再介绍下线性筛素数方法  
    bool noprime[MAX];
    vector  prime;
    void Prime(int n){
        for (int i = 2; i <= n; i ++){
            if (!noprime[i]){
                prime.push_back(i);
            }
            for (int j = 0; j < prime.size() && prime[j] * i <= n; j ++){
                noprime[prime[j]*i] = 1;
                if (i % prime[j] == 0)  break;		//每个数只被他自身最小的素因子筛去
            }
        }
    }
    
      利用了每个合数必有一个最小素因子。 每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。 代码中体现在: if(i%pr[j]==0)break; pr数组中的素数是递增的,当i能整除pr[j],那么i*pr[j+1]这个合数肯定被pr[j]乘以某个数筛掉。 因为i中含有pr[j],pr[j]比pr[j+1]小。接下去的素数同理。所以不用筛下去了。 在满足i%pr[j]==0这个条件之前以及第一次满足改条件时,pr[j]必定是pr[j]*i的最小因子。     三、结合线性筛素数算法的优化算法 基于这个线性筛素数算法,我们可以很容易地得到某个数的最小素因子。 因为当i%pr[j]!=0的时候,最小素因子pr[j]与i互质,满足积性函数的条件,可以直接得到f(i*pr[j])=f(i)*f(pr[j]). 不过当i%pr[j]==0时我们必须根据该积性函数本身的特性进行计算.或者在筛的同时保存并递推些附加信息.总之要O(1)求得f(i*pr[j])及完成递推附加信息.   下面的两个例子是欧拉函数phi和约数个数.这两个是最常用和最有优化价值的。 利用上面的性质都可以很容易地把前n个用O(n)时间推出来. 当然,利用这个性质还可以对其他积性函数进行优化,这里仅介绍两个常用和有优化价值的。   1)欧拉函数(phi) 传统的算法: 对于某素数p且n|p(n能整除p) if( (n/p) % i == 0 ) phi(n)=phi(n/p)*i; else phi(n)=phi(n/p)*(i-1);   这个传统算法的性质正好用在筛素数算法中. p为n的最小素因子,当n/p包含该因子p,则phi(n)=phi(n/p)*i;否则phi(n)=phi(n/p)*(i-1); p即pr[j], n/p即i, n即i*pr[j]了.  
    int phi[MAX];
    bool noprime[MAX];
    vector  prime;
    void Euler(int n){
        phi[1] = 0;
        for (int i = 2; i <= n; i ++){
            if (!noprime[i]){
                prime.push_back(i);
                phi[i] = i - 1;
            }
            for (int j = 0; j < prime.size() && prime[j] * i <= n; j ++){
                noprime[prime[j]*i] = 1;
                if (i % prime[j] == 0){
                    phi[prime[j]*i] = phi[i] * prime[j];
                }
                else{
                    phi[prime[j]*i] = phi[i] * phi[prime[j]];
                }
            }
        }
    }
    
      2)约数个数(divnum) 约数不能像phi那么自然,但还是有不错的方法. 约数个数有个性质 divnum(n)=(e1+1)*(e2+1)...(ei表示n的第i个质因数的个数.) 传统方法就是对每个数分解质因数,获得各因数个数再用上式.   开一个空间e[i]表示最小素因子的次数 这次说直接点: 筛到i 第j个素数   对于divnum 如果i|pr[j] 那么 divnum[i*pr[j]]=divsum[i]/(e[i]+1)*(e[i]+2)         //最小素因子次数加1 否则 divnum[i*pr[j]]=divnum[i]*divnum[pr[j]]          //满足积性函数条件   对于e 如果i|pr[j]  e[i*pr[j]]=e[i]+1;       //最小素因子次数加1 否则 e[i*pr[j]]=1; //pr[j]为1次
    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    ubuntu下文件安装与卸载
    webkit中的JavaScriptCore部分
    ubuntu 显示文件夹中的隐藏文件
    C语言中的fscanf函数
    test
    Use SandCastle to generate help document automatically.
    XElement Getting OuterXML and InnerXML
    XUACompatible meta 用法
    Adobe Dreamweaver CS5.5 中文版 下载 注册码
    The Difference Between jQuery’s .bind(), .live(), and .delegate()
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4113985.html
Copyright © 2011-2022 走看看