【模板】扩展中国剩余定理(EXCRT)

传送门:洛谷:p4777


中国剩余定理(CRT)

xxxa1(modp1)a2(modp2)an(modpn) { x ≡ a 1 ( mod p 1 ) x ≡ a 2 ( mod p 2 ) ⋮ x ≡ a n ( mod p n )

给定 a1,a2,...,an,p1,p2,..,pn a 1 , a 2 , . . . , a n , p 1 , p 2 , . . , p n ( pi p i 分别为互不相同的素数),求解满足上式的最小非负整数解 x x
M=i=1npi M = ∏ i = 1 n p i Mi=Mpi M i = M p i tiMi1(modpi) t i ≡ M i − 1 ( mod p i )
显然, xi=1naiMiti(modM) x ≡ ∑ i = 1 n a i M i t i ( mod M )


扩展中国剩余定理(EXCRT)

xxxa1(modb1)a2(modb2)an(modbn) { x ≡ a 1 ( mod b 1 ) x ≡ a 2 ( mod b 2 ) ⋮ x ≡ a n ( mod b n )

要求同上,唯一不同的是 b1,b2,...,bn b 1 , b 2 , . . . , b n 为任意正整数,不要求为素数,也不要求互质。
采用增量法:
设当前已求出满足前 k k 项的答案 xk(modmodk) x k ( mod m o d k ) modk=lcm(b1,b2,...,bk) m o d k = l c m ( b 1 , b 2 , . . . , b k )
必然存在整数 g g ,使得:
xk+g×modkxk+1(modmodk+1) x k + g × m o d k ≡ x k + 1 ( mod m o d k + 1 )
也即:
xk+g×modkak+1(modbk+1) x k + g × m o d k ≡ a k + 1 ( mod b k + 1 )
故:
g×modk+g×bk+1=ak+1xk g × m o d k + g ′ × b k + 1 = a k + 1 − x k
变成了扩展欧几里得的形式。
先求出 f×modk+f×bk+1=gcd(modk,bk+1) f × m o d k + f ′ × b k + 1 = g c d ( m o d k , b k + 1 )
g=f×ak+1xkgcd(modk,bk+1) g ′ = f ′ × a k + 1 − x k g c d ( m o d k , b k + 1 ) (若 ak+1xk a k + 1 − x k 不能被 gcd(modk,bk+1) g c d ( m o d k , b k + 1 ) 整除,则无解)
不断增量即可。


代码

这里的 a,b a , b 的定义可以参考洛谷题面。

#include
#define RI register
#define gc getchar
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n;
ll a,b,ans,mod,Mod,res,tp,x,y,k;

char c;
template<class T>
inline void rd(T &x)
{
    c=gc();x=0;
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);c=gc()) x=x*10+(c^48);
}

inline ll gcd(ll A,ll B){return (!B)?A:gcd(B,A%B);}

inline void exgcd(ll A,ll B)
{
    if(!B){x=1;y=0;return;}
    exgcd(B,A%B);
    k=x;x=y;y=k-y*(A/B);
}

inline ll mul(ll x,ll y,ll md)//O(1)快速乘
{ll d=floor(1.0*x/md*y+1e-8);ll re=x*y-d*md;return re<0?re+md:re;}

int main(){
    rd(n);
    rd(mod);rd(ans);
    for(RI int i=2;i<=n;++i){
        rd(a);rd(b);tp=gcd(mod,a);//先求出gcd会快一些
        if(ans%a==b){mod=mod/tp*a;continue;}
        res=((b-ans)%a+a)%a;res/=tp;Mod=a/tp;
        exgcd(Mod,mod/tp);
        y=(mul(y,res,Mod)+Mod)%Mod;
        Mod*=mod;ans=(ans+mul(y,mod,Mod))%Mod;
        mod=Mod;
    }
    printf("%lld\n",ans);
}

你可能感兴趣的:(exgcd,CRT及EXCRT)