• 数论,数学


    gcd and lcm

    Code

    int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    

    gcd的几条性质

    [gcd(x^a-1,x^b-1)=x^{gcd(a,b)}-1 ]

    证明:
    (gcd(x^a-1,x^b-1))
    (=gcd(x^b-1,x^a-x^b))
    (=gcd(x^b-1,x^b(x^{a-b}-1)))
    (=gcd(x^b-1,x^{a-b}-1))

    [gcd(fib[i],fib[j])=fib[gcd(i,j)] ]

    (fib[]) 为广义斐波那契数列)

    证明:
    (gcd(fib[i+j],fib[j]))
    (=gcd(fib[j],fib[i+j]-fib[j]))
    (=gcd(fib[j],fib[i-1]*fib[j]+fib[i]*fib[j+1]-fib[j]))
    (=gcd(fib[j],fib[i]*fib[j+1]))
    (=gcd(fib[j],fib[i]))

    线性筛

    int pr[maxn],tot;
    bool check[maxn];
    void init(int n){
        check[1]=1;
        for(int i=2;i<=n;i++){
            if(!check[i]){
                pr[++tot]=i;
            }
            for(int j=1;j<=tot&&i*pr[j]<=n;j++){
                check[i*pr[j]]=1;
                if(i%pr[j]==0)break;
            }
        }
    }
    

    理论上来讲 (n) 以内的质数个数大约在 (n/ln(n)) 个左右

    欧拉定理

    [a^{varphi(n)}≡1(\% n)(gcd(a,n)=1) ]

    (S={x_1,x_2,...,x_{varphi(n)}}) 为所有与 (n) 互质且 (le n) 的数。
    显然 (x_i≡x_j(i≠j)(\% n)) 不成立。
    再设 (T={a*x_1,a*x_2,...,a*x_{varphi(n)}})
    (ecause gcd(a,n)=1)
    ( herefore a*x_i≡a*x_j(i≠j)(\% n)) 不成立
    ( herefore S=T)
    ( herefore prod_{i=1}^{varphi(n)}a*x_i≡prod_{i=1}^{varphi(n)}x_i(\% n))
    ( herefore a^{varphi(n)}≡1(\% n))

    扩展欧拉定理

    [a^bequiv egin{cases} a^{bmodvarphi(p)},\,&gcd(a,\,p)=1\ a^b,&gcd(a,\,p) e1,\,b<varphi(p)\ a^{bmodvarphi(p)+varphi(p)},&gcd(a,\,p) e1,\,bgevarphi(p) end{cases} pmod p ]

    费马小定理

    (a^{p-1}≡1(\% p)(p ext{ is prime}))

    Code

    (O(n))(1-n) 的欧拉函数

    void init(int n){
    	phi[1]=1;	
    	for(int i=2;i<=n;i++){
    		if(!check[i]){
    			pr[++tot]=i;
    			phi[i]=i-1;
    		}
    		for(int j=1;j<=tot&&i*pr[j]<=n;j++){
    			check[i*pr[j]]=1;
    			if(i%pr[j]==0){
    				phi[i*pr[j]]=phi[i]*pr[j];
    				break;
    			}
    			else phi[i*pr[j]]=phi[i]*phi[pr[j]];
    		}
    	}
    }
    

    (O(sqrt{n}))(n) 的欧拉函数

    int phi(int n){
        int x=n,ret=n;
        for(int i=2;i*i<=n&&x>1;i++){
            if(x%i==0){
                ret=ret/i*(i-1);
                while(x%i==0)x/=i;
            }
        }
        if(x>1)ret=ret/x*(x-1);
        return ret;
    }
    

    逆元

    逆元的引入

    在做组合数取模的时候,常常要求((a/b)\%p^{[1]}),然而不同于加减乘,除法取模没有((a/b)\%p=(a\%p/b\%p)\%p)的性质。因此,我们引入乘法逆元的概念。

    (a* b≡1(\%p)),则设(b=inv(a)),称(b)(a)的逆元,满足((a*b)\%p=(a\%p*b\%p)\%p)。这样,除法转换为乘法,就可以了。

    所有的有理数都有一个与其对应的逆元。因此,对于两个整数(A,B),要计算(frac{A}{B})(实数除法)时,(A)不一定要被(B)整除。

    对于两个取模过的数,逆元是怎么输出商的?它实际上是在对给定的取模过的数(a,b),找最小的两个(A,B),满足(A=x* p+a,B=y* p+b,A\%B=0),并返回(A/B)

    求逆元的几种常用方法

    1. 扩展欧几里得

    欧几里得定理

    想必都知道$$gcd(a,b)=gcd(b,a%b)$$

    解关于(x,y)的方程(ax+by=gcd(a,b))

    首先,我们先解出方程的一个特解,再通过特解推出其余的通解即可。

    如何求特解

    我们来看下面两个方程:

    [ax_1+by_1=gcd(a,b) ]

    [bx_2+(a\%b)y_2=gcd(b,a\%b) ]

    (ecause gcd(a,b)=gcd(b,a\%b),)

    ( herefore ax_1+by_1=bx_2+(a\%b)y_2)

    (ecause a\%b=a-floor(a/b)* b^{[2]})

    ( herefore ax_1+by_1=ay_2+b(x_2-floor(a/b)* y_2))

    由等式两边的系数关系得$$x_1=y_2$$$$y_1=x_2-floor(a/b)* y_2$$
    于是形成了一种递归关系,可用递归解决。

    递归终止状态

    我们知道在计算最大公约数的过程中,(b)最终会等于(0),此时(a=gcd(A,B)),因此,这时方程化为(a* x=gcd(A,B)),解得(x=1,y=0)

    如何求通解

    求得一组特解之后,我们发现,对于方程(ax+by=gcd(a,b)),当(x)增加(b/gcd)(y)减少(a/gcd)时,等式仍成立。

    证明

    (ax)项增加(a* b/gcd)(by)项减少(a* b/gcd)

    于是可求得所有通解。

    如何求最小非负整数解

    此处以(x)为例,(y)同理。我们让(x)一直减(B/gcd)直至求出最小解,即让(x\%(B/gcd))即可。

    解关于(x,y)的方程(Ax+By=C)

    我们发现,当(C)不能整除(gcd(A,B))时,方程就不能化为(ax+by=gcd(a,b))的形式,因此就无解。否则有无数解,将方程两边同时除以(frac{C}{gcd(A,B)})求解即可。

    Code
    typedef long long D;
    D egcd(D a,D b,D &x,D &y){
    	if(b==0){
    		x=1;
    		y=0;
    		return a;
    	}
    	D ans=egcd(b,a%b,x,y),tmp=x;
    	x=y;
    	y=tmp-a/b*y;
    	return ans;
    }
    D cal(D a,D b,D c){
    	D x,y,g=egcd(a,b,x,y);
    	if(c%g!=0)return -1;
    	b=abs(b/g);
    	x=(x*(c/g)%b+b)%b;
    	return x;
    }
    

    利用扩展欧几里得求乘法逆元

    因为$$a* x≡1(%p)$$
    所以$$a* x+b* y=1$$
    此时,若(1\%gcd(a,b)≠1),即(gcd(a,b)≠1),则该方程无解。
    否则,设特解为(x_0),最小非负整数解(x=x_0\%m)。当(m<0)时,由于计算机取模一个负数与数学上的意义不同,所以应把模数取绝对值。当(x_0<0)时,取模的结果是一个负数,所以把答案加上(m)即可。

    复杂度为(log)级。

    Code

    typedef long long D;
    D egcd(D a,D b,D &x,D &y){
    	if(b==0){
    		x=1;
    		y=0;
    		return a;
    	}
    	D ans=egcd(b,a%b,x,y),tmp=x;
    	x=y;
    	y=tmp-a/b*y;
    	return ans;
    }
    D cal(D a,D m){
    	D x,y,g=egcd(a,m,x,y);
    	if(g!=1)return -1;
    	m=abs(m/g);
    	x=(x%m+m)%m;
    	return x;
    }
    

    2. 利用费马小定理

    (p)为质数时(a^{p-1}≡1(\%p)) ,对(a* x≡1(\%p))(x=a^{p-2}\%p)

    复杂度为(log)级。

    Code

    typedef long long D;
    D qpow(D x,D y,D p){
    	D ans=1;
    	while(y){
    		if(y&1)ans=ans*x%p;
    		x=x*x%p;
    		y>>=1;
    	}
    	return ans;
    }
    D cal(D a,D p){
    	return qpow(a,p-2,p);
    }
    

    组合数取模(Lucas 定理)

    由于题目中给的(p)一般都是质数,所以下面我们默认(p)为质数

    1. 错误方法

    由上面的结论,我们得出$$C(n,m)=frac{n!}{m!(n-m)!}=n!* inv(m!)* inv((n-m)!)$$
    直接使用扩展欧几里得或费马小定理求逆元来实现除法取模。

    此方法的错误之处在于,对(a* x≡1(\%p),a)有逆元的前提条件时(a,p)互质。当(a,p)不互质,即(a)(p)的倍数时,不存在逆元,也就无法计算。

    比如计算(C(7,5)\%5),正确答案应该是(frac{7* 6}{1* 2}\%5=21\%5=1),但计算过程中出现了(5)的倍数,取模(5)之后就变为(0),因此最后答案输出了(0)

    2. Lucas定理

    lucas定理可避免上述情况。

    递归式:

    (lucas(n,m,p))(C(n,m)\%p) (p)为质数),则

    [lucas(n,m,p)=C(n\%p,m\%p,p)* lucas(n/p,m/p,p) ]

    此处的(C(n,m,p))可直接通过逆元计算。

    复杂度为(log)级。

    证明

    Code

    typedef long long D;
    D fac[100001];
    void preparefac(D n,D p){
    	fac[0]=1;
    	for(D i=1;i<=n;i++){
    		fac[i]=i*fac[i-1]%p;
    	}
    }
    D qpow(D x,D y,D p){
    	D ans=1;
    	while(y>0){
    		if(y%2)ans=ans*x%p;
    		x=x*x%p;
    		y/=2;
    	}
    	return ans;
    }
    D cal(D x,D y){
    	return qpow(x,y-2,y);
    }
    D Div(D x,D y,D p){
    	return x*cal(y,p)%p;
    }
    D C_(D n,D m,D p){
    	if(m>n)return 0;
    	return Div(Div(fac[n],fac[m],p),fac[n-m],p);
    }
    D C(D n,D m,D p){
    	if(!m)return 1;
    	return C_(n%p,m%p,p)*C(n/p,m/p,p)%p;
    }
    

    线性递推求逆元

    首先 (1^{-1}≡1(\%p))
    (p=k* i+r)
    (k* i+r≡0(\%p))
    等式两边乘 (i^{-1}* r^{-1})
    (k* r^{-1}+i^{-1}≡0(\%p))
    ( herefore i^{-1}≡-k* r^{-1}(\%p))
    ( herefore i^{-1}≡-floor(frac{p}{i})* (p\%i)^{-1}(\%p))

    Code

    inv[1]=1;
    inv[i]=(p-p/i)*inv[p%i]%p;
    

    阶乘逆元

    (i) 的阶乘逆元等于 (i-1) 的阶乘逆元乘以 (i) 的逆元。

    Code

    facinv[i]=facinv[i-1]*inv[i]%p;
    

    CRT

    用于求解一元线性同余方程组 (xequiv a_ipmod{m_i})
    过程:

    1. (b_i=prod_{j eq i}m_j)
    2. (c_iequiv b_i^{-1}pmod{m_i})
    3. (ans=sum_{i=1}^n a_ib_ic_ipmod{prod_i m_i})

    证明

    对于(iin[1,n])(ansequiv a_i+sum_{j eq i} a_jb_jc_jpmod{m_i}),由于(m_i|b_j(j eq i))( herefore ansequiv a_ipmod{m_i})

    exCRT

    对于多个方程的情况,考虑将方程两两合并。

    对于两个方程的情况(xequiv a_1pmod{m_1},xequiv a_2pmod{m_2})

    转换:(x=m_1s+a_1=m_2t+a_2 Rightarrow m_1s-m_2t=a_2-a_1),使用exgcd求解

    (gcd(m_1,m_2) mid a_2-a_1)时无解

    高端数论

    积性函数

    (f(xy)=f(x)f(y)(xperp y))

    完全积性函数

    (f(xy)=f(x)f(y))

    欧拉函数

    定义

    (varphi(n)=sum_{i=1}^n [iperp n])

    性质

    [varphi(p)=p-1(p ext{ is prime}) ]

    显然,除了它本身以外的数都和该质数互质。

    [varphi(p^k)=p^k-p^{k-1}(p ext{ is prime}) ]

    (p^k) 不互质的数就是 (p) 的倍数,有 (frac{p^k}{p}=p^{k-1}) 个。

    [varphi(a*b)=varphi(a)*varphi(b)(gcd(a,b)=1) ]

    (S_x={) 所有与 (x) 互质且 (le x) 的数 (}) 。显然 (|S_x|=varphi(x))
    (ecause gcd(a,b)=1,)
    ( herefore S_{a*b})(S_a,S_b) 一一对应。
    ( herefore |S_{a*b}|=|S_a|*|S_b|,)(varphi(a*b)=varphi(a)*varphi(b))

    [varphi(2*n)=varphi(n)(n\% 2=1) ]

    (varphi(2)=1) ,易证。

    [varphi(n)=varphi(frac{n}{p})*p(p|frac{n}{p}) ]

    (varphi(frac{n}{p})=frac{n}{p}*prod (1-frac{1}{p_i}))
    (varphi(n)=p*frac{n}{p}*prod (1-frac{1}{p_i})=p*varphi(frac{n}{p}))

    [varphi(n)=varphi(frac{n}{p})*(p-1)(p ext{ is prime},p|n,gcd(p,frac{n}{p})=1) ]

    (varphi(p)=p-1) ,易证。

    [sum_{d|n}varphi(d)=n ]

    (f(n)=sum_{d|n}varphi(d))
    (gcd(x,y)=1) 时, (f(x)*f(y)=xprod_{p_i是x的质因子}(1-frac{1}{p_i})*yprod_{p_i是y的质因子}(1-frac{1}{p_i})=x*yprod_{p_i是x*y的质因子}(1-frac{1}{p_i})=f(x*y))
    ( herefore f(n)) 是积性函数。
    (f(p^k)=sum_{i=0}^k varphi(p^i)=p^k)
    于是我们把 (n) 分解质因数:
    (n=prod p_i^{k_i})
    (f(n)=prod f(p_i^{k_i})=prod p_i^{k_i}=n)

    公式

    (varphi(x)=xprod (1-frac{1}{p_i}))
    (p_i)(x) 的第 (i) 个质因子, (x≥2)(varphi(1)=1)
    根据唯一分解定理, (x=prod p_i^{k_i})
    ( herefore varphi(x)=prod varphi(p_i^{k_i})=prod (p_i^{k_i}-p_i^{k_i-1})=xprod (1-frac{1}{p_i}))

    其他常用函数

    (epsilon(n)=[n=1])

    (id(n)=n)

    (1(n)=1)

    (sigma_k(n)=sum_{dmid n}d^k)

    其中(omega(n))表示(n)的本质不同质因子个数,是一个积性函数。

    狄利克雷卷积

    ((f*g)(n)=sum_{dmid n}f(d)g(frac{n}{d}))

    例子

    [epsilon=mu*1 ]

    [sigma_0=1*1 ]

    [sigma=id*1 ]

    [varphi=mu*id ]

    (varphi=mu*id)证明

    (varphi*1=id Rightarrow varphi*1*mu=id*mu Rightarrow varphi*epsilon=mu*id)

    莫比乌斯反演

    (f(n)=sum_{dmid n}g(d)Rightarrow g(n)=sum_{dmid n}mu(d)f(frac{n}{d}))


    注:
    [1] 在本文中,(\%)表示取模运算,等价于( ext{mod})
    [2] (floor(x))表示(lfloor x floor)
  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number (考虑负数的情况)
    8. String to Integer (整数的溢出)
    7. Reverse Integer (整数的溢出)
    LeetCode Minimum Size Subarray Sum
    LeetCode Course Schedule II
    Linux 文件缓存 (一)
    LeetCode Tries Prefix Tree
    Linux : lsof 命令
    LeetCode Binary Tree Right Side View
  • 原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/9863156.html
Copyright © 2020-2023  润新知