以上兩種算法都是用於解決現行同餘方程組問題,只不過中國剩餘定理是擴展中國剩餘定理的一個特殊化解法。ios
中國剩餘定理給出瞭如下的一元線性同餘方程組:
有解的斷定條件,並用構造法給出了在有解狀況下解的具體形式。
中國剩餘定理說明:假設整數\(m_1,m_2, ... ,m_n\)兩兩互質,則對任意的整數:\(a_1,a_2, ... ,a_n\),方程組 有解,而且通解能夠用以下方式構造獲得:
設是整數\(m_1,m_2, ... ,m_n\)的乘積,並設
是除了mi之外的n- 1個整數的乘積。
設則有
則方程組 的通解形式爲
該解在模M的意義下惟一。
若是把該解帶入原方程,則發現正確性顯然。
代碼實現實際上是模擬上面的過程,其中求逆元的過程能夠用費馬小定理和擴展歐幾里得,這裏博主選用的是擴展歐幾里得。算法
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<sstream> #include<queue> #include<map> #include<vector> #include<set> #include<deque> #include<cstdlib> #include<ctime> #define dd double #define ll long long #define ull unsigned long long #define N 11 #define M number using namespace std; int n; ll a[N],b[N],x[N],all=1,ans; inline ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1; y=0; return a; } ll gcd=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return gcd; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),all*=a[i]; for(int i=1;i<=n;i++){ ll now=all/a[i]; ll y; ll gcd=exgcd(now,a[i],x[i],y); x[i]=(x[i]%a[i]+a[i])%a[i]; // printf("%d\n",x[i]); } for(int i=1;i<=n;i++){ ans+=((all/a[i]*b[i])%all*x[i])%all; ans%=all; } printf("%lld\n",ans); return 0; }
運用中國剩餘定理的條件是模數兩兩互素,那麼擴展中國剩餘定理的使用條件是任意模數。這裏給出證實。
對於一個方程組來講,第一個方程的通解很明顯能用擴展歐幾里得算法得出。
把該解寫成通解的形式,帶入第二個式子。例如該通解爲\(x_0+t*m\),再帶入第二個方程式後,我麼要作的是找到一個t使該通解一樣知足第二個式子。以此類推。
注意,不管任什麼時候候,該通解在模已經解決的方程的模數的最小公倍數下惟一。代碼:(由於long long乘long long可能會溢出,這裏用快速乘)spa
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<sstream> #include<queue> #include<map> #include<vector> #include<set> #include<deque> #include<cstdlib> #include<ctime> #define dd double #define ll long long #define ld long double #define ull unsigned long long #define N 100100 #define M number using namespace std; inline ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1; y=0; return a; } ll gcd=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-a/b*y; return gcd; } ll n; ll a[N],b[N]; inline ll ksc(ll x,ll y,ll mod){ ll z=(ld)x/mod*y; ll res=(ull)x*y-(ull)mod*z; return (res%mod+mod)%mod; } int main(){ scanf("%lld",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&a[i],&b[i]); ll m=a[1],x0=b[1]; for(int i=2;i<=n;i++){ ll t,q; ll g=exgcd(m,a[i],t,q); ll now_m=m/g*a[i]; t=ksc(t,((b[i]-x0)/g+a[i])%a[i],a[i]); x0=(x0%now_m+ksc(t,m,now_m))%now_m; m=now_m; } printf("%lld",x0); return 0; }