扩展中国剩余定理(exCRT)

首先 了解扩展中国剩余定理 你真的一点都不需要了解中国剩余定理
不过 你需要了解逆元 扩展欧几里得
所以…
如果不会逆元的请看这里(想学中国剩余定理也有 − − − − − > -----> > 详解数论从入门到入土
想更好地把逆元应用到欧拉函数、欧拉定理、费马小定理、中国剩余定理请看这里 − − − − − > -----> >数论1
想更好地把逆元应用到组合数、扩展欧几里得请看这里 − − − − − > -----> >数论2
咳咳很好

ok说正事
什么是扩展中国剩余定理 就是下面这个:

{ n ≡ a 1 ( m o d    m 1 ) n ≡ a 2 ( m o d    m 2 ) . . . n ≡ a k ( m o d    m k )   \begin{cases} n\equiv a_1(\mod m_1)\quad \\ n\equiv a_2(\mod m_2)\quad \\... \\ n\equiv a_k(\mod m_k)\quad \ \end{cases} na1(modm1)na2(modm2)...nak(modmk) 
其中 ( m 1 , m 2 , . . . , m k ) (m_1,m_2,...,m_k) (m1,m2,...,mk)不一定是 1 1 1,求 n n n的最小非负整数解

S o l u t i o n : Solution: Solution:
假设已经求出前 k − 1 k-1 k1个方程组成的同余方程组的一个解为 x x x
M = ∏ i = 1 k − 1 m i M=\prod_{i=1}^{k-1}m_i M=i=1k1mi,前 k − 1 k-1 k1个方程的最小非负整数解为 x x x
则前 k − 1 k-1 k1个方程组的通解为 x + M i        ( i ∈ Z ) x+Mi\,\,\,\,\,\,(i∈Z) x+Mi(iZ)
对于加入的第 k k k个方程 我们就是要找一个 t ∈ Z t∈Z tZ使得
x + M t ≡ a k ( m o d    m k ) x+Mt\equiv a_k(mod\,\,m_k) x+Mtak(modmk)
M t ≡ a k − x ( m o d    m k ) Mt\equiv a_k-x(mod\,\,m_k) Mtakx(modmk)
对于这个式子我们已经可以通过扩展欧几里得求解
若该同余式无解,则整个方程组无解
若有,则前 k k k个同余式组成的方程组的一个解解为 x k = x + M t x_k=x+Mt xk=x+Mt
所以整个算法的思路就是求解 k k k次扩展欧几里得

模板题:洛谷P4777 【模板】扩展中国剩余定理(EXCRT)
代码:

#include
using namespace std;
#define N int(1e5+10)
#define reg register
typedef long long ll;
inline void read(ll &x){
	ll s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
	x=s*w;
}
inline ll slowmul(ll x, ll y, ll m){
	while(x<0)x+=m;
	while(y<0)y+=m;
	if(x<y)swap(x,y);
	ll ret=0;
	while(y){
		if(y&1)(ret+=x)%=m;
		(x<<=1)%=m,y>>=1;
	}
	return ret;
}
void Extended_Greatest_Common_Divisor(ll a, ll b, ll &x, ll &y){
	if(!b){x=1,y=0;return;}
	Extended_Greatest_Common_Divisor(b,a%b,y,x);y-=(a/b)*x;
}
ll n,ai[N],bi[N];
ll Extended_Chinese_Remainder_Theorem(){
	ll x,y,a,b,c,M=bi[1],ans=ai[1],gcd;
	for(ll i=2;i<=n;i++){
		a=M,b=bi[i],c=(ai[i]-ans%b+b)%b,gcd=__gcd(a,b);
		if(c%gcd)return -1;
		a/=gcd,b/=gcd,c/=gcd;
		Extended_Greatest_Common_Divisor(a,b,x,y);
		x=slowmul(x,c,b),ans+=x*M,M*=b;
		ans=(ans%M+M)%M;
	}
	return ans;
}
int main(){
	read(n);
	for(reg ll i=1;i<=n;i++)read(bi[i]),read(ai[i]);
	printf("%lld\n",Extended_Chinese_Remainder_Theorem());
}

顺带一下中国剩余定理的模板题吧:
[TJOI2009]猜数字

#include
using namespace std;
typedef long long ll;
inline ll slowmul(ll x, ll y, ll mod){
    if(x<0)x+=mod;if(y<0)y+=mod;
    if(y>x)swap(x,y);
    ll ret=0;
    while(y){
        if(y&1)(ret+=x)%=mod;
        (x+=x)%=mod,y>>=1;
    }
    return ret;
}
ll k,a[20],b[20],t[20];
void Extended_Greatest_Common_Divisor(ll n, ll m, ll &x, ll &y){
    if(!m){x=1,y=0;return;}
    Extended_Greatest_Common_Divisor(m,n%m,y,x);y-=(n/m)*x;
}
ll Chinese_Remainder_Theorem(){
    ll ans=0,lcm=1,x,y;
    for(int i=1;i<=k;i++)lcm*=b[i];
    for(int i=1;i<=k;i++){
        t[i]=lcm/b[i];
        Extended_Greatest_Common_Divisor(t[i],b[i],x,y);
        x=(x%b[i]+b[i])%b[i];
        ans=(ans+slowmul(slowmul(t[i],a[i],lcm),x,lcm))%lcm;
    }
    return (ans+lcm)%lcm;
}
int main(){
    scanf("%lld",&k);
    for(int i=1;i<=k;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=k;i++)scanf("%lld",&b[i]);
    printf("%lld\n",Chinese_Remainder_Theorem());
}


你可能感兴趣的:(数论)