码迷,mamicode.com
首页 > 其他好文 > 详细

中国剩余定理和扩展中国剩余定理

时间:2019-08-17 18:22:38      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:前置   efi   目的   ref   lcm   art   最小   cpp   unsigned   

也许更好的阅读体验


前置知识

快速乘
扩展欧几里得定理
同余方程

中国剩余定理(CRT)

目的

求最小的正整数\(x\),使其满足

\(\begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases}\)

其中 \(m_1,m_2\dots m_n\)互质

求法

\(\begin{aligned}M=\prod ^{n}_{i=1}m_{i}\end{aligned}\)
\(\omega _{i}=\dfrac {M}{m_{i}}\)

\(\omega_i^{-1}\)\(\omega_i\)\(mod\ M\)下的逆元

则有
\(\begin{aligned}x=\sum ^{n}_{i=1}a_{i}\omega_{i}\omega_{i}^{-1} mod\ M\end{aligned}\)

当对\(m_i\)取模时,除了有\(\omega_i\)的项,其余项都是\(m_i\)的倍数,也就是说它们\(mod\ m_i\)是为\(0\)的,最后得到的结果就是\(a_i\)

\(m_1,m_2\dots m_n\)互质
为了保证是最小正整数解,我们乘以\(\omega_i\)的逆元,这样保证了其不会过大

Code

#define ll long long
#define ull unsigned long long

void ex_gcd (ll a,ll b,ll &x,ll &y)
{
    if (!b){    x=1,y=0;return;}
    ex_gcd(b,a%b,x,y);
    int tmp=x;
    x=y,y=tmp-a/b*y;
}

ll mul (ll x,ll y,const ll mod)//快速乘
{
    x%=mod,y%=mod;
    ll z=(long double)x*y/mod;
    ll ans=(ull)x*y-(ull)z*mod;
    return (ans+mod)%mod;
}

ll crt (int *a,int *m,int n)
{
    ll M=1,ans=0;
    for (int i=1;i<=n;++i)  M*=m[i];
    for (int i=1;i<=n;++i){
        ll ni,jk;
        ex_gcd(M/m[i],m[i],ni,jk);//ni 逆元
        ans=(ans+mul(mul(M/m[i],a[i],M),ni,M))%M;
    }
    return ans;
}

扩展中国剩余定理(EXCRT)

目的

求最小的正整数\(x\),使其满足

\(\begin{cases} x\equiv a_{1}\left( mod\ m\right) \\ x\equiv a_{2}\left( mod\ m_{2}\right) \\ \vdots \\ x\equiv a_{n}\left( mod\ m_{n}\right) \end{cases}\)

其中 \(m_1,m_2\dots m_n\)不一定互质

解法

对于\(CRT\)而言,这里的条件变为\(m\)之间可以不互质了
显然是不能向原来那样直接求了
考虑已经知道了前\(i-1\)个方程的答案\(x\)
设前\(i-1\)\(m\)的最小公倍数\(lcm(m1,m2\dots m_{i-1})=M\)
现在考虑第\(i\)个方程
\(x\equiv a_i\left(mod\ m_i\right)\)
我们知道前\(i-1\)个方程的最小解为\(x\),那么其通用解就是\(x+kM\)
因为\(kM\)对前\(i-1\)\(m\)取模肯定是等于\(0\)
那么考虑了第\(i\)个方程后的解应也是如上的一个形式
就设为\(x+kM\)
那么我们就是要求关于\(k\)的这样的方程
\(kM+x\equiv a_i\left(mod\ m_i\right)\)
其中\(x,a_i,m_i\)都是已知的
这就是一个简单的同余方程了
\(kM-pm_i=a_i-x\)
其中两个未知数\(k,p\)
\(ex_gcd\)求解即可
无解条件就是上述方程无解

code

#define ll long long
#define ull unsigned long long

ll ex_gcd (ll a,ll b,ll &x,ll &y)
{
    if (!b){    x=1,y=0;return a;}
    ll g=ex_gcd(b,a%b,x,y);
    int tmp=x;
    x=y,y=tmp-a/b*y;
    return g;
}

ll mul (ll a,ll b,ll mod)//快速乘
{
    a%=mod,b%=mod;
    ll c=(long double)a*b/mod;
    ll ans=(ull)a*b-(ull)c*mod;
    return (ans+mod)%mod;
}

ll ex_crt (ll *a,ll *m,int n)
{
    ll ans=a[1]%m[1],M=m[1];
    for (int i=2;i<=n;++i){
        ll gcd,x,y,c=(a[i]%m[i]-ans%m[i]+m[i])%m[i];
        gcd=ex_gcd(M,m[i],x,y);
        if (c%gcd)  return -1;
        x=mul(x,c/gcd,m[i]/gcd);
        ll lm=M;
        M=M/gcd*m[i];
        ans=((ans+mul(x,lm,M)%M)%M+M)%M;
    }
    return ans;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

中国剩余定理和扩展中国剩余定理

标签:前置   efi   目的   ref   lcm   art   最小   cpp   unsigned   

原文地址:https://www.cnblogs.com/Morning-Glory/p/11369321.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!