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

版权声明:侵删,转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82177534

传送门:洛谷:p4777


中国剩余定理(CRT)

{ x a 1 ( mod p 1 ) x a 2 ( mod p 2 ) x a n ( mod p n )

给定 a 1 , a 2 , . . . , a n , p 1 , p 2 , . . , p n ( p i 分别为互不相同的素数),求解满足上式的最小非负整数解 x
M = i = 1 n p i M i = M p i t i M i 1 ( mod p i )
显然, x i = 1 n a i M i t i ( mod M )


扩展中国剩余定理(EXCRT)

{ x a 1 ( mod b 1 ) x a 2 ( mod b 2 ) x a n ( mod b n )

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


代码

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

#include<bits/stdc++.h>
#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);
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/82177534