1. 程式人生 > >拓展中國剩余定理(ex_crt)

拓展中國剩余定理(ex_crt)

pan pri 簡單 lib 模板 維護 .... code ack

一般來講,crt(中國剩余定理)比較常見,而ex_crt(拓展中國剩余定理)不是很常用

但是noi 2018偏偏考了這麽個詭異的東西...

所以這裏寫一個ex_crt模板

模型:

技術分享圖片

求一個x滿足上述方程,其中a1,a2...an不一定互質

解法:

設存在一特解x0滿足前k個方程組,且LCM(a1,a2...ak)=M

則前k個方程的通解x=x0+k·M(k∈Z)

這是很顯然的,因為技術分享圖片 (1<=i<=k)

那麽第k+1個方程等價於:求使技術分享圖片t

這顯然可以使用ex_gcd求解(移項即可)

那麽剩余部分就簡單了:不斷維護一個x0,最後返回x0即可

#include <cstdio>
#include 
<cmath> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #include <queue> #include <stack> #define ll long long using namespace std; ll n; ll a[100005]; ll b[100005]; ll pow_add(ll x,ll y,ll mod) { ll ans=0; while(y) {
if(y%2) { ans+=x; ans%=mod; } y/=2; x+=x; x%=mod; } return ans; } ll gcd(ll x,ll y) { if(y==0) { return x; } return gcd(y,x%y); } void ex_gcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1; y
=0; return; } ex_gcd(b,a%b,x,y); ll t=x; x=y; y=t-(a/b)*x; } ll ex_crt() { ll M0=a[1]; ll ans=b[1]; for(int i=2;i<=n;i++) { ll r=gcd(M0,a[i]); ll bb=((b[i]-ans)%a[i]+a[i])%a[i]; if(bb%r) { return -1; } bb/=r; ll M=M0/r; ll aa=a[i]/r; ll x,y; ex_gcd(M,aa,x,y); x=pow_add(x,bb,aa); ans+=x*M0; M0*=aa; ans=(ans%M0+M0)%M0; } return (ans%M0+M0)%M0; } int main() { scanf("%lld",&n); for(int i=1;i<=n;i++) { scanf("%lld%lld",&a[i],&b[i]); } printf("%lld\n",ex_crt()); return 0; }

拓展中國剩余定理(ex_crt)