zoukankan      html  css  js  c++  java
  • 同余

    同余和同余方程

    (frac{a-b}{m})为整数,则称(a)(b)(m)同余,用(aequiv b pmod{m})表示.
    同余方程,即同余式中含有未知数,一般来说都有多组解.

    扩展欧几里得

    扩展欧几里得算法用于求解形如(ax+by=c)的方程.

    裴蜀定理

    (a),(b)是整数,且(gcd(a,b)=d),那么对于任意的整数(x),(y),(ax+by)都一定是(d)的倍数,一定存在整数(x),(y),使(ax+by=d)成立.

    特解

    分为3种情况求解.
    情况1 (c=gcd(a,b))
    在辗转相除法中,通过回溯求出方程的一组特解.
    具体操作:

    1. (b=0)时,(x=1),(y=0).
    2. 否则(x=y),(y=x-frac{a}{b}*y).
      证明:在进行操作2时,(a)(b)是分别由下一步的(b)(a\%b)回溯而来.设(k=lfloor{frac{a}{b}} floor)(此证明中(a,b)均是这一步的而非下一步的),下一步(x)(y)的值分别为(x')(y').
      如果我们令(y=x'),则有(egin{equation} left{ egin{aligned} overset{}ax+by=gcd(a,b) \ by'+(a\%b)*x=gcd(a,b) \ end{aligned} ight. end{equation})
      ( herefore kbx=b*(y'-y))
      ( herefore kx=y'-y)
      ( herefore y=y'-kx=y'-lfloor{frac{a}{b}} floor*x)
    long long exgcd(long long a,long long b,long long &x,long long &y) {
        if(b==0) {
            x=1;
            y=0;
            return a;
        }
        long long r=exgcd(b,a%b,x,y);
        long long t=y;
        y=x-(a/b)*y;
        x=t;
        return r;
    }
    

    情况2 (c=k*gcd(a,b))((k)为整数)
    此时,把第一种情况((c=gcd(a,b)))的解(x)(y)分别乘以(k),得到方程的解.

    情况3 (gcd(a,b) mid c)
    根据裴蜀定理,原方程无整数解.

    通解

    假设特解为(x_0),(y_0).
    则通解为(x=x_0+k*frac{b}{gcd(a,b)}),(y=y_0-k*frac{a}{gcd(a,b)})

    乘法逆元

    (amequiv 1pmod{p})时,称(m)(a)(p)的乘法逆元.
    余数的四个性质是可加性,可减性,可乘性可乘方性,但余数不能直接除.
    在求(frac{a}{b}\%m)时,我们需要借助乘法逆元.
    与倒数类似,设(k)(b)的乘法逆元,则(frac{a}{b}\%m=a*k\%m).

    扩展欧几里得求乘法逆元

    (amequiv 1pmod{p})
    ( herefore am+pq=1)
    如果(gcd(a,p)=1),就可以用扩展欧几里得来求乘法逆元.

    long long inv(long long a,long long p) {
        long long x,y;
        exgcd(a,p,x,y);
        while(x<0) x+=p;
        return x%p;
    }
    

    费马小定理求乘法逆元

    费马小定理:对于质数(p),(a^{p-1}equiv 1pmod {p})
    ( herefore a*a^{p-2}equiv 1pmod {p})
    ( herefore)(p)是质数时,(a^{p-2})(a)的乘法逆元.
    费马小定理求乘法逆元涉及到快速幂.

    long long poww(long long a,long long b,long long k) { //快速幂
        if(b==1) return a%k;
        long long p=1;
        p=poww(a,b/2,k);
        p=p*p%k;
        if(b%2) p=p*a%k;
        return p;
    }
    long long inv(long long a,long long p) {
        long long t=poww(a,p-2,p);
        while(t<0) t+=p;
        return t;
    }
    

    中国剩余定理

    中国剩余定理由儿子孙子提出.
    这个定理用于求解形如(egin{equation} left{ egin{aligned} overset{}x &equiv y_1pmod{m_1} \ x &equiv y_2pmod{m_2} \ &{ vdots } \ x &equiv y_npmod{m_n} end{aligned} ight. end{equation})的同余方程组.
    求解这样的方程组,需要找出(n)个数(p_1,p_2,)...(,p_n).
    对于每个(p_i) , (p_iequiv y_ipmod{m_i}),(p_iequiv 0pmod{m_j(j ot = i)}).
    最后将全部(p_i)加起来,就是方程的一个解.显然,两个相邻解的差为(lcm(m_1,m_2,)...(,m_n)).
    将问题进一步简化,对于每个(p_i) , (p_iequiv 1pmod{m_i}),(p_iequiv 0pmod{m_j(j ot = i)}).
    最后计算全部(p_i*y_i)的和.
    (ecause p_iequiv 0pmod{m_j(j ot = i)})
    ( herefore p_iequiv 0pmod{lcm(m_1,m_2,...,m_i-1,m_i+1,...,m_n)})
    (k_i=lcm(m_1,m_2,...,m_i-1,m_i+1,...,m_n)),(p_i=l*k_i).
    (l*k_iequiv 1pmod{m_i})
    (l*k_i=-s*m_i+1).
    (l*k_i+s*m_i=1)
    此时就可以用乘法逆元求解.
    但如果有任意(i,j(1le i,jle n))使(gcd(m_i,m_j) ot =1),扩展欧几里得就会无解,所以必须满足对于任意(i,j(1le i,jle n)),(gcd(m_i,m_j)=1).

    long long crt() {
        long long lcm=1,ans=0;
        for(long long i=1;i<=n;i++) lcm*=x[i];
        for(long long i=1;i<=n;i++) {
            long long mi=lcm/x[i];
            long long ni,y;
            exgcd(mi,x[i],ni,y);
            ans+=(mi*ni%lcm)*y[i]%lcm;
            ans%=lcm;
        }
        while(ans<0) ans+=lcm;
        return ans;
    }
    

    扩展中国剩余定理

    扩展中国剩余定理用于解决上文提到过得不互质的同余方程组.它实际上就是同余方程的合并.
    有如下同余方程组
    (egin{equation} left{ egin{aligned} overset{}x &equiv y_1pmod{m_1} \ x &equiv y_2pmod{m_2} end{aligned} ight. end{equation})
    (egin{equation} left{ egin{aligned} overset{}x &=y_1+k_1*m_1 \ x &=y_2-k_2*m_2 end{aligned} ight. end{equation})
    ( herefore y_1+k_1*m_1=y_2-k_2*m_2)
    ( herefore k_1*m_1+k_2*m_2=y_2-y_1)
    由裴蜀定理知,当((y_2-y_1) mid gcd(m_1,m_2))时原方程无解.
    否则就可以用扩展欧几里得求出(k_1,k_2)的值.
    最后将解转化为(xequiv y_1+k_1*m_1pmod{lcm(m_1,m_2)}).
    如果有多于2个同余方程,就用这种方法继续合并方程.

    long long excrt(){
        long long m=x[1],b=y[1],t,g,x1,y1;
        for(int i=2;i<=n;i++){
            g=exgcd(m,x[i],x1,y1); 
            if((y[i]-b)%g)  return -1;       
            x1*=(y[i]-b)/g;
            t=x[i]/g;
            x1=(x1%t+t)%t;    
            b=m*x1+b;
            m=m/g*x[i];   
        }
        while(b<0) b+=m;
        return b%m;
    }
    

    BSGS

    BSGS算法的名字很形象,全称是Bady Step Giant Step(大步小步),它用于求解形如(a^xequiv bpmod{m})的高次同余方程.
    根据费马小定理,如果用暴力求解这种方程,那么最坏情况下时间复杂度为(O(m)).
    (m)比较大时,就必须用BSGS算法.
    (x=k_1*lceil{sqrt{m}} ceil-k_2),即(a^{k_1*lceil{sqrt{m}} ceil-k_2}equiv bpmod{m})
    ( herefore a^{k_1*lceil{sqrt{m}} ceil}equiv b*a^{k_2}pmod{m})
    我们将全部(b*a^{k_2})的值都存入哈希表(或是map或vector)中,再枚举全部(a^{k_1*lceil{sqrt{m}} ceil}),寻找有没有(b*a^{k_2})与之匹配.
    时间复杂度为(O(sqrt{m})).
    此处用map实现哈希表.

    long long bsgs(long long a,long long b,long long p) {
        if(a==0&&b!=0) return -1;
        if(b==1) return 0;
        int m=ceil(sqrt(p)),k;
        long long num1=1,num2=1;
        map <long long, long long> _HASH;
        _HASH.clear();
        for(int i=1; i<=m; i++,num2=num2*a%p) _HASH[num2*b%p]=i-1;                  
        for(int i=1; i<=m+1; i++) {
            num1=num1*num2%p;    
            if(_HASH.count(num1)) return i*m-_HASH[num1];                        
        }
        return -1;
    }
    

    BSGS必须保证(gcd(a,m)=1).

    扩展BSGS

    扩展BSGS基于BSGS,它加了一些前期处理使(gcd(a,m) ot=1)时也能求解.
    (k_1=gcd(a,m)),若(k_1 mid b)则原方程无解.
    否则(a^{x-1}*frac{a}{k_1}equiv frac{b}{k_1}pmod{frac{m}{k_1}})
    如果(gcd(a,frac{m}{k_1}) ot =1),就继续重复这一过程.
    最终将方程化为(a^{k-t}*frac{a^t}{k_1k_2{cdots}k_t}equiv frac{b}{k_1k_2{cdots}k_t}pmod{frac{m}{k_1k_2{cdots}k_t}}).
    (M=k_1k_2{cdots}k_t) , (a^{k-t}*frac{a^t}{M}equiv frac{b}{M}pmod{frac{m}{M}})
    (ecause gcd(a,frac{m}{M})=1)
    ( herefore gcd(frac{a^t}{M},frac{m}{M})=1)
    ( herefore)可以通过计算(frac{a^t}{M})的逆元来将(frac{a^t}{M})移到右式.
    (frac{a^t}{M})的逆元为(T),则(a^{k-t}equiv frac{b}{M}*Tpmod{frac{m}{M}}).
    此时可直接用BSGS求解.
    但有可能出现方程的解小于(t)的情况,所以需先枚举(a^i(0le ile t)equiv bpmod{m})的情况.

    long long exbsgs(long long a,long long b,long long p) {
        if(a==0&&b!=0) return -1;
        if(b==1) return 0;
        long long ki,t=0,M=1,s=1;
        while((ki=gcd(a,p))!=1) {
        	if(b%ki!=0) return -1;
        	t++;
        	b/=ki,p/=ki;
        	M=M*(a/ki)%p;
        	if(M==b) return t;
    	}
        long long m=ceil(sqrt(p)),k,num1=1,num2=1;
        b=b*inv(M,p)%p;
        map <long long, long long> _HASH;
        _HASH.clear();
        for(int i=1; i<=m; i++,num2=num2*a%p) _HASH[num2*b%p]=i-1;                  
        for(int i=1; i<=m+1; i++) {
            num1=num1*num2%p;    
            if(_HASH.count(num1)) return i*m-_HASH[num1]+t;                        
        }
        return -1;
    }
    
    不忘初心 砥砺前行
  • 相关阅读:
    ABAP 程序中的类 沧海
    ABAP类的方法(转载) 沧海
    More than 100 ABAP Interview Faq's(2) 沧海
    SAP and ABAP Memory总结 沧海
    ABAP Frequently Asked Question 沧海
    ABAP System Reports(Additional functions) 沧海
    ABAP Questions Commonly Asked 1 沧海
    ABAP Tips and Tricks 沧海
    ABAP System Fields 沧海
    ABAP 面试问题及答案(一):数据库更新及更改 SAP Standard (转) 沧海
  • 原文地址:https://www.cnblogs.com/gzezfisher/p/equiv.html
Copyright © 2011-2022 走看看