1. 程式人生 > >擴充套件歐幾里得,線性同餘方程 poj1845

擴充套件歐幾里得,線性同餘方程 poj1845

 

定理:對於任意整數a,b存在一堆整數x,y,滿足ax+by=gcd(a,b)

int exgcd(int a,int b,int &x,int &y){
    if(b==0){x=1,y=0;return a;}
    int d=exgcd(b,a%b,x,y);
    int z=x;x=y;x=z-y*(a/b);
    return d;
}

當d可以整除c時,一般方程ax+by=c的一組特解求法:

  1.求ax+by=d的特解x0,y0

  2.ax+by=c的特解為(c/d)x0,(c/d)y0

上述方程的通解:(c/d)x0+k(b/d) ,(c/d)y0-k(a/d)

乘法逆元:b,m互質,並且b整除a,則存在x,有a/b = a*x(mod m),即a/b模m的結果和a*x模m的結果是相同的,這個x稱為b的模m的乘法逆元,記作b^(-1) (mod m)

  可得b*b^(-1) = 1(mod m)

  那麼當m是質數時,根據費馬小定理,有b^(m-1)=1(mod m),那麼b的逆元就是b^(m-2)

  如果只是保證b,m互質,那麼解同餘方程b*x=1(mod m)可以求出x

所以當遇到除法取模運算時,可以先求出逆元,轉換成乘法取模運算

/*
如果單獨是個A,那麼就可以分解質因數後用公式求約數個數
那麼B個A相乘,其約數個數就是mul{1+p^1+p^2...+p^B*ci} 
結果是比數列求和後再相乘,每項等比數列的結果是 
(pi^(B*ci+1)-1)/(pi-1) mod9901,
1.pi-1不是9901的倍數,(pi-1)^(9901-2)就是逆元 
2.pi-1是9901的倍數,逆元不存在,但是pi mod 9901=1。。。 

先把A分解質因數,再等比數列求和(快速冪+逆元), 
*/ #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define ll long long #define mod 9901 int m,p[200],c[200]; void divide(int n){ m=0; for(int i=2;i*i<=n;i++) if(n%i==0){ p[++m]=i,c[m]=0; while
(n%i==0) n/=i,c[m]++; } if(n>1) p[++m]=n,c[m]=1; } ll pow(ll a,ll b){ ll res=1; while(b){ if(b&1) res=res*a%mod; a=a*a%mod; b>>=1; } return res; } int main(){ ll a,b,ans=1; scanf("%lld%lld",&a,&b); divide(a);//分解質因數 for(int i=1;i<=m;i++){ if((p[i]-1)%mod==0){ ans=ans*(b*c[i]+1)%mod; continue; } //求分子和分母逆元 ll x=pow(p[i],b*c[i]+1)%mod; x=(x-1+mod)%mod; ll y=pow(p[i]-1,mod-2)%mod; ans=ans*x%mod*y%mod; } printf("%lld\n",ans); }

 

求解同餘方程:a*x=b(mod m)等價於a*x-b是m的倍數,等價於a*x+m*y=b,當gcd(a,m)|b時,有解

按照拓展歐幾里得演算法,可解得特解x=x0*b/gcd(a,m)就是原線性同餘方程的一個解

  通解為所有模m/gcd(a,m)與x同餘的整數

求解同餘方程:noip2012:a*x=1(mod b)的最小整數解 

#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll a,b,x,y;
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){x=1;y=0;return a;}
    ll d=exgcd(b,a%b,x,y);
    ll z=x; x=y,y=z-y*(a/b);
    return d; 
} 
int main(){
    cin >> a >> b;
    exgcd(a,b,x,y);//x可能是負數 
    cout << (x%b+b)%b<<endl;    
}