1. 程式人生 > >[洛谷P4777] [模板] 擴展中國剩余定理

[洛谷P4777] [模板] 擴展中國剩余定理

不定方程 需要 我們 ++ targe scan lld target blank

擴展中國剩余定理,EXCRT。

題目傳送門

重溫一下中國剩余定理。

中國剩余定理常被用來解線性同余方程組:

x≡a[1] (mod m[1])

x≡a[2] (mod m[2])

......

x≡a[n] (mod m[n])

但是中國剩余定理只能解決m[1]、m[2]......m[n]兩兩互質的情況。

對於m[1]、m[2]......m[n]不兩兩互質的情況,我們需要用其它的方法解決。

假設我們已經處理到了第i個方程,設ans為前i-1個方程的解,ms為m[1]*m[2]*...*m[i-1]。

那麽前i-1個方程組的通解為ans+t*ms(t為任意值)。

而這些解不是都滿足第i個方程。

所以我們需要求出一個k,使ans+k*ms≡a[i](mod m[i])。

設c=a[i]-ans,原同余方程轉換為不定方程:k*ms+kk*m[i]=c(kk不重要)。

使用exgcd求解即可。

由不定方程的性質,如果(a[i]-ans)不能被gcd(ms,m[i])整除,則無解。

若有解,令c/=gcd(ms,m[i]),m[i]/=gcd(ms,m[i])。

k=k*c(註意要mod m[i])求出k的最小非負解(這道題需要快速乘防爆long long)。

最後更新一下:ans=ans+k*ms,ms=ms*m[i],並讓ans取模新的ms得到最小解。

對於初值:ans=a[1](顯然滿足第一個方程),ms=m[1]。

然後從第二個方程開始算就好了。

 1 #include<cstdio>
 2 #define ll long long
 3 
 4 int n;
 5 ll a[100005],m[100005];
 6 ll ms,ans;
 7 
 8 ll exgcd(ll ea,ll eb,ll &x,ll &y)
 9 {
10     if(!eb)
11     {
12         x=1,y=0;
13         return ea;
14     }
15     ll ret=exgcd(eb,ea%eb,y,x);
16     y-=ea/eb*x;
17     return
ret; 18 } 19 20 ll mul(ll x,ll y,ll mod) 21 { 22 ll ret=0; 23 while(y) 24 { 25 if(y&1)ret=(ret+x)%mod; 26 x=(x+x)%mod; 27 y>>=1; 28 } 29 return ret; 30 } 31 32 int main() 33 { 34 scanf("%d",&n); 35 for(int i=1;i<=n;i++)scanf("%lld%lld",&m[i],&a[i]); 36 ans=a[1],ms=m[1]; 37 for(int i=2;i<=n;i++) 38 { 39 ll k,kk; 40 ll c=((a[i]-ans)%m[i]+m[i])%m[i]; 41 ll g=exgcd(ms,m[i],k,kk); 42 //if(c%g)return 0; 43 m[i]/=g,c/=g; 44 k=mul(k,c,m[i]); 45 ans=ans+k*ms; 46 ms*=m[i]; 47 ans=(ans%ms+ms)%ms; 48 } 49 printf("%lld",ans); 50 return 0; 51 }

[洛谷P4777] [模板] 擴展中國剩余定理