首先 了解扩展中国剩余定理 你真的一点都不需要了解中国剩余定理
不过 你需要了解逆元 扩展欧几里得
所以…
如果不会逆元的请看这里(想学中国剩余定理也有
−
−
−
−
−
>
----->
−−−−−> 详解数论从入门到入土
想更好地把逆元应用到欧拉函数、欧拉定理、费马小定理、中国剩余定理请看这里
−
−
−
−
−
>
----->
−−−−−>数论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}
⎩⎪⎪⎪⎨⎪⎪⎪⎧n≡a1(modm1)n≡a2(modm2)...n≡ak(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
k−1个方程组成的同余方程组的一个解为
x
x
x
设
M
=
∏
i
=
1
k
−
1
m
i
M=\prod_{i=1}^{k-1}m_i
M=∏i=1k−1mi,前
k
−
1
k-1
k−1个方程的最小非负整数解为
x
x
x
则前
k
−
1
k-1
k−1个方程组的通解为
x
+
M
i
(
i
∈
Z
)
x+Mi\,\,\,\,\,\,(i∈Z)
x+Mi(i∈Z)
对于加入的第
k
k
k个方程 我们就是要找一个
t
∈
Z
t∈Z
t∈Z使得
x
+
M
t
≡
a
k
(
m
o
d
m
k
)
x+Mt\equiv a_k(mod\,\,m_k)
x+Mt≡ak(modmk)
即
M
t
≡
a
k
−
x
(
m
o
d
m
k
)
Mt\equiv a_k-x(mod\,\,m_k)
Mt≡ak−x(modmk)
对于这个式子我们已经可以通过扩展欧几里得求解
若该同余式无解,则整个方程组无解
若有,则前
k
k
k个同余式组成的方程组的一个解解为
x
k
=
x
+
M
t
x_k=x+Mt
xk=x+Mt
所以整个算法的思路就是求解
k
k
k次扩展欧几里得
模板题:洛谷P4777 【模板】扩展中国剩余定理(EXCRT)
代码:
#include<bits/stdc++.h>
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<bits/stdc++.h>
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());
}