中国剩余定理及EX及单层EXLucas定理讲解
NOIP前恶补数论的感觉真是神清气爽啊!
教练问我们有什么知识点不会,一问到数论马上就GG了。
花了2个小时学习中国剩余定理。
好了废话少说,我们进入正题。
首先膜拜一下中国南北朝时期的数学家孙子(不是孙武)。
用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:

求最小的正整数解x。
当m1--mn相互互质时可以求解(若不互质可以通过扩展中国剩余定理求解)。
分几步求解:
1.求一下∏ni=1mi记为m
2.设Mi=m/mi
3.设ti满足Mi$\times$ti≡1(mod mi)
4.x=∑ni=1Mi$\times$ai$\times$ti
至于第四步的原因
因为我们保证Mi是除了当前mi之外所有模数的倍数,所以我们的第4步的理论依据是对于任意K(K≠i),Mi$\times$ai$\times$ti ≡ 0(mod mk),所以Mi$\times$ai$\times$ti≡ai(mod mi).所以第4步成立。
问题来了,Mi和ai好办,如何求ti?
我们注意到Mi$\times$ti≡1(mod mi)。考虑扩展GCD,把它转换成ax+by=1解同余方程。
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
ll tmp=x;
x=y,y=tmp-a/b*y;
return ;
}
解完之后,就可以求辣!
ll China()
{
ll x,ans=0,y;
for(int i=1;i<=n;i++)
m*=in[i];
for(int i=1;i<=n;i++)
{
M[i]=m/in[i];
exgcd(M[i],in[i],x,y);
ans=(ans+a[i]*x*M[i])%m;
}
return (ans+m)%m;
}
中国剩余定理最基础题目的网站https://neooj.com:8082/oldoj/problem.php?id=1322
上代码
#include<cstdio>
typedef long long ll;
ll M[11];
ll t[11];
ll a[11];
ll in[11];
ll m=1;
ll n;
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
ll tmp=x;
x=y,y=tmp-a/b*y;
return ;
}
ll China()
{
ll x,ans=0,y;
for(int i=1;i<=n;i++)
m*=in[i];
for(int i=1;i<=n;i++)
{
M[i]=m/in[i];
exgcd(M[i],in[i],x,y);
ans=(ans+a[i]*x*M[i])%m;
}
return (ans+m)%m;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&in[i],&a[i]);
ll ans=China();
printf("%lld",ans);
}
下面讲解扩展Lucas定理。
普通的Lucas定理长这样:
C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p(p为质数)
上个代码
#include<cstdio>
#define mod 10007
int fac[mod+2];
int inv[mod+2];
int lucas(long long n,long long m)
{
if(n<m)
return 0;
if(n<mod&&m<mod)
return fac[n]*inv[m]%mod*inv[n-m]%mod;
return lucas(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
}
int main()
{
fac[0]=1,inv[mod-1]=mod-1;
for(int i=1;i<=mod;i++) fac[i]=fac[i-1]*i%mod;
for(int i=mod-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
long long n,m;
scanf("%I64d%I64d",&n,&m);
printf("%d\n",lucas(n,m));
}
对于p不是质数的情况我们可以向中国剩余定理的方向讨论。
若不是素数,将p分解质因数,将C(n,m)分别按照Lucas的方法求对p的质因数的模,然后用中国剩余定理合并。比如计算C(10,3)%14。C(10,3)=120,14有两个质因数2和7,120%2=0,120%7=1,这样用(2,0)(7,1)找到最小的正整数8即是答案,即C(10,3)%14=8非常简单。注意,这里只适用于p分解完质因数后每个质因数只出现一次.至于多次的,我不会(大写GG,有兴趣的可以学习一下.)
EX中国剩余定理
因为模数不是质数,所以我们采用两两合并的思想。

x=a1+m1$\times$y1
x=a2+m2$\times$y2
两方程联立,x≡a1+m1$\times$y1(mod lcm(m1,m2))
蒋神blog中有证明
https://www.cnblogs.com/ShuraK/p/7905790.html##11
上code:P4777 【模板】扩展中国剩余定理(EXCRT)
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
ll gcd=exgcd(b,a%b,x,y);
ll tmp=x;
x=y;
y=tmp-a/b*y;
return gcd;
}
ll pow(ll x,ll y,ll mod)
{
ll ans=0;
while(y)
{
if(y&1)
ans=(ans+x)%mod;
x=(x+x)%mod;
y/=2;
}
return ans;
}
ll China()
{
ll M=m[1];
ll ans=a[1];
for(int i=2;i<=n;i++)
{
ll A=M,B=m[i],d=((a[i]-ans)%B+B)%B,x,y;
ll gcd=exgcd(A,B,x,y);
x=pow(x,d/gcd,B/gcd);
M*=B/gcd;
ans=(ans+x*A)%M;
}
return (ans%M+M)%M;
}

浙公网安备 33010602011771号