zoukankan      html  css  js  c++  java
  • 数论知识小结 [基础篇]

    数论知识小结 [基础篇]

    (latest updated on 2020.08.12)


    符号((a,b)=gcd(a,b))

    乘除(a|b ightarrow b=ka (kin N^+))

    (sum)求和,(prod)求积

    任意(forall),存在(exists)

    $lfloor x floor $ 向下取整,$lceil x ceil $ 向上取整

    ([a,b])区间,通常指整数即([a,b]cap )

    调和级数

    数学上,调和级数为(H_n=sum_{i=1}^{n}frac{1}{i})

    OI中,我们常用调和级数分析(sum_{i=1}^nfrac{n}{i}approx nln n)

    把它近似看成是(f(x)=frac{n}{x})([1,n])上的积分,它的原函数(F(x)=nln x)

    (egin{aligned} sum_{i=1}^nfrac{n}{i}approx int_1^nf(x) dx=F(n)-F(1)=nln n-napprox nln nend{aligned})

    附:广义调和级数 (egin{aligned} H^z_n=sum_{i=1}^{n}frac{1}{i^z} end{aligned})它的无穷形式为黎曼函数(egin{aligned}zeta(z)=H^{z}_{infty}end{aligned})

    [ ]

    向下取整的性质/数论分段

    性质:$lfloor frac{n}{ab} floor =lfloor frac{lfloor frac{n}{a} floor }{b} floor $

    [ ]

    数论分段:即对于(i=[1,n]),把(i)按照(lfloor frac{n}{i} floor)的值分成(O(sqrt n))段,(通常为(2cdot sqrt n)段左右)

    证明:对于(ileq sqrt n),显然只有(sqrt n)个不同的值

    对于(i>sqrt n),此时(frac{n}{i}<sqrt n),也只有(sqrt n)个不同的值

    [ ]

    素数/质数/质数密度

    对于(x>1),若( exists yin[2,n-1],y|x),则(x)是一个质数,下文称素数集合为(prime)集合

    (n)以内的素数个数用函数(pi(n)=|primecap[1,n]|)表示,素数密度在渐进意义上是(O(log n))

    即可以认为(pi(n)=O(frac{n}{log n}))(实际在(n)较小时完全看不出这一点)

    (n)的唯一分解: (n=prod_{p_iin prime} p_i^{c_i})

    朴素的素数判别法:

    一个显然方法的如果(x)不是质数,则(exists yin [2,sqrt n] ,y|x)

    所以可以朴素写出一个(O(sqrt n))的素数判别法

    利用这一点预先处理小素数,每次只判断素数,可以写出一个(O(pi(sqrt n)))的素数判别法

    朴素的质因数分解法:

    即求(n=prod p_i^{c_i},p_iin prime),其中(sum c_ileq log _2^n)

    由于对于一个数(n),最多存在一个(yin prime cap [sqrt n,n],y|n),因此可以先分解掉(y<sqrt n)的部分,剩下的一个就知道了

    void Factor(int n){
        for(int i=2;i*i<=n;++i) if(n%i==0)  
            while(n%i==0) printf("%d ",i),n/=i; // 分解掉<sqrt(n)的部分
        if(n>1) printf("%d ",n); // 如果还剩下,那么就是>sqrt(n)的一个质数
    }
    

    复杂度是(O(sqrt n +log n))

    更优化的只枚举质数作为因子,复杂度是(O(pi(sqrt n)+log n))

    [ ]

    朴素的素数筛法:埃氏筛

    对于([2,n])每个数(i)(x=ki(k>1))均不是质数,直接枚举复杂度为调和级数(O(nln n))

    更优化的,对于([2,n])中每个质数(i)(x=ki(k>1))均不是质数,由于素数密度为(O(log n)),所以可以近似认为是(O(nlog log n))(实际我不会证明。。)

    线性筛(欧拉筛)

    筛素数知识一个基础,可以筛很多函数,尤其是适用于积性函数

    直接上代码背板子好了

    int notpri[N],prime[N],primecnt;
    void Sieve(){
        notpri[1]=1;
        for(int i=2;i<=n;++i) {
            if(!notpri[i]) prime[++primecnt]=i;
            for(int j=1; j<=primecnt && 1ll*i*prime[j]<=n;++j){
                notpri[i*prime[j]]=1;
                if(i%prime[j]==0) break;
            }
        }
    }
    
    

    其中(imod prime_j= 0)意味着后面的数已经被(frac{i}{prime_j})筛掉了,所以可以break

    复杂度是带有一定常数的(O(n)),还可以用来筛其他的一些函数

    [ ]

    [ ]

    (gcd, ext{lcm})

    最大公因数( ext{gcd(greatest common divisor)})常用(gcd(x,y)=(x,y))表示

    最小公倍数( ext{lcm(least common multiple)})

    特别的:((a,0)=a)

    (gcd(a,b))可以用辗转相除法(也称为欧几里得算法),即利用性质((a,b)=(amod b,b))

    每次递归调用(gcd(b,amod b))即可,边界为((a,0)=a)

    复杂度分析:

    首先是取模的分析,对于(forall a,b,age b),必然满足(amod b leq frac{a}{2})

    所以每次取模至少会减少一倍,复杂度为(O(log a))

    [ ]

    附:扩展欧几里得算法

    用于求解不定方程(ax+by =1)的一组解((x,y))

    存在解的条件是((a,b)=1),否则((a,b)|ax+by),即(ax+by>1)

    用类似求( ext{gcd})的方法求出

    (ax+by=1)

    (( amod b)cdot x+ lfloor frac{a}{b} floorcdot bcdot x + by=1)

    (( amod b)cdot x+ bcdot (lfloor frac{a}{b} floorcdot x + y)=1)

    那么如果求出((amod b)cdot x'+bcdot y'=1)的解

    (x'=x,y'=lfloor frac{a}{b} floor cdot x+y)

    (x=x',y=y'-lfloor frac{a}{b} floor x)

    每次都递归求出$(amod b) cdot x+ by =1 $

    复杂度与(gcd)相同,最后的((a,b)=a=1,b=0)是边界条件,此时(x+0cdot y=1)的一组解是((1,0))

    写成代码

    // ax + by =1
    int Exgcd(int a,int b,int &x,int &y) {
        if(b==0){ 
            if(a!=1) return 0; // (a,b)!=1 ,不存在解
            x=1,y=0; // 初始解
            return 1;
        } 
        Exgcd(b,a%b,y,x),y-=a/b*x; // 带入上面的式子,注意这里带入的是(b,a%b),所以x,y要反过来
        return 1;
    }
    

    注意求出的(x,y)不保证为正数

    [ ]

    [ ]

    [ ]

    因数个数

    似乎没有找到规范的函数定义,所以下称(d(n))

    (d(n)=|{i|iin[1,n]and i|n}|)

    对于(n=prod p_i^{c_i}),列一条小学的公式(d(n)=prod (c_i+1))

    因数个数一个非常松的上界是(O(sqrt n)),证明这里略去

    实际上,搜索得到的上界大致是

    maxn=10^ 1  max= 4
    maxn=10^ 2  max= 12
    maxn=10^ 3  max= 32
    maxn=10^ 4  max= 64
    maxn=10^ 5  max= 128
    maxn=10^ 6  max= 240
    maxn=10^ 7  max= 448
    maxn=10^ 8  max= 768
    maxn=10^ 9  max= 1344
    maxn=10^10  max= 2304
    maxn=10^11  max= 4032
    maxn=10^12  max= 6720
    maxn=10^13  max= 10752
    maxn=10^14  max= 17280
    maxn=10^15  max= 26880
    maxn=10^16  max= 41472
    maxn=10^17  max= 64512
    maxn=10^18  max= 103680
    

    可以看到,因数个数是非常少的

    附:

    质因数个数(Omega(n)=|primecap [1,n]|),非常松的上界是(Omega(n)=O(log n))

    约数和函数(sigma(n)=sum_{i|n}i)

    [ ]

    费马小定理/欧拉定理/欧拉函数/阶

    [ ]

    费马小定理: 对于任意质数(P,x>0,x^{p-1}equiv 1 pmod P)

    [ ]

    欧拉函数:(varphi(n))([1,n-1])中与(n)互质的数个数,特别的(varphi(1)=1)

    (n=prod p_i^{c_i})其中(p_i)是质数,(c_i>0),则(varphi(n)=prod p_i^{c_i-1}(p_i-1)=nprodfrac{p_i-1}{p_i})

    对于可以通过类似筛素数的方法求出来([1,n])(varphi(i))

    对于数(n),需要采用质因数分解求出,朴素的做法为(O(sqrt n)),用( ext{Pollard's Rho})算法复杂度更低

    [ ]

    欧拉定理:对于任意数(P>1,x>0,x^{varphi(P)}equiv 1pmod P)

    推论:(x^cequiv x^{cmod varphi (P)} pmod P)

    很显然,费马小定理是欧拉定理的特殊情况

    [ ]

    阶:对于((a,n)=1)的整数,满足(a^r≡1 pmod n) 的最小整数(r),称为(a)(n)的阶,以下简称(d(a))

    显然(a^i mod n)构成了一个以(r)为最小正周期的循环

    性质:根据欧拉定理(a^{varphi(n)}mod n=1),所以有(d(a)|varphi(n))

    求解阶:先对于 (varphi(n))质因数分解,然后可以

    1.依次枚举每个因数判断是否有(a^imod n=1),取最小的(i),复杂度为(O(sqrt nlog n))

    2.设(varphi(n)=p_i^{c_i}),令(x=varphi(P)),从(x)开始,如果(a^{frac{x}{p_i}}mod n=1),则(x ightarrow frac{x}{p_i})

    预处理复杂度受限于质因数分解(下文有介绍)

    单次查询复杂度上限是(O(log ^2 P))(为快速幂复杂度乘上(sum c_i))

    [ ]

    模逆元

    对于任意数(x>1,P>1,(x,P)=1),存在一个数(frac{1}{x}equiv ypmod P)

    (xyequiv 1 pmod P)(y)(x)的一个模逆元

    (P)为质数时,由于(x^{P-1}equiv 1 pmod P),所以(yequiv x^{P-2}pmod P)(x)的一个逆元

    (P)不为质数时,如果已知(varphi (P)),可以类似得做,否则可以构造(acdot x+bcdot P=1),用扩展欧几里得算法求出一组合法解((a,b)),则(a)即为一个答案

    [ ]

    原根/指标

    原根:一个数(P)有原根的条件是他可以表示为(P=1,2,4,p,2p,p^n(pin prime))

    对于(P),令(d(x))(x)(P)的原根,若存在(d(x)=varphi(P)),则(x)(P)的一个原根

    找原根:

    (varphi(P)=prod p_i^{c_i}),其中(p_i)是质数

    由于(d(x)|varphi(P)),如果(d(x)<varphi(P))那么必然存在一个(x^{frac{varphi(P)}{p_i}}equiv 1pmod P)

    所以先求一遍质因数分解,然后快速幂判断就可以做到(O(log ^2 P))判断原根

    显然原根不唯一

    已经被证明对于任意的(P)如果存在原根,则其最小原根最多是(O(P^{frac{1}{4}}))级别的

    [ ]

    指标:

    对于一个数(P)和它的一个原根(x),对于(gcd(y,P)=1),则(y)一定可以用(x^i)表示,那么(i)就是(y)的指标

    同时,(y)(P)的阶就是(d(y)=frac{varphi(P)}{gcd(varphi(P),i)}),可以认为是数列(a_j=icdot jmod varphi(P))的周期问题

    可以使用( ext{BSGS})算法在(O(sqrt Plog P))或者(O(sqrt P))的时间内求出一个数的指标

    (关于去掉(log P):只需要处理出模逆元直接累乘,每次用( ext{Hash Table})访问即可)

    指标在二次剩余的较劣做法中也有应用,同时也可以直接套用性质用于阶的求解

    [ ]

    快速乘

    (x,yin[0,P-1],Pleq 10^{18},xcdot y mod P)

    直接乘法会爆long long

    可以用类似快速幂的方法写,复杂度为(O(log P))

    typedef long long ll;
    typedef unsigned long long ll;
    void qmul(ll x,ll y,ll P){
        ll res=0;
        for(;y;y>>=1,x=(x+x)%P) if(y&1) res=(res+x)%P;
        return res;
    }
    

    另一种方法是强行用long double 保证精度,然后计算的时候用unsigned long long 溢出回来,(O(1))但是很奇怪,通常不会挂

    typedef long long ll;
    typedef unsigned long long ll;
    void qmul(ll x,ll y,ll P){
        ull z=(long double)x/P*y;
        ll res=(ull)x*y-(ull)z*P;
        return (res%P+P)%P;
    }
    

    [ ]

  • 相关阅读:
    win10 uwp 弹起键盘不隐藏界面元素
    win10 uwp 存放网络图片到本地
    win10 uwp 存放网络图片到本地
    sublime Text 正则替换
    sublime Text 正则替换
    win10 uwp 绘图 Line 控件使用
    win10 uwp 绘图 Line 控件使用
    AJAX 是什么?
    什么是 PHP SimpleXML?
    PHP XML DOM:DOM 是什么?
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13092822.html
Copyright © 2011-2022 走看看