中国剩余定理详解

来源:互联网 发布:dos运行java程序 编辑:程序博客网 时间:2024/06/05 20:44

引例:

一堆物品,三个三个取余两个,五个五个取余三个,七个七个取余两个,问有多少物品

x≡2(mod3)

x≡3(mod5)

x≡2(mod7)

我们知道,70能被5和7整除,且70mod3=1,21能被3和7整除,且21mod5=1,15能被3和5整除,且15mod7=1

由此易知,一个可行的解为 70*2+21*3+15*2=233,3,5,7的最小公倍数为105,最小的解即为233mod105=23

由上述引例,我们知道了求解同余方程组的一般思路,那么如何推广到1~n,满足

x≡a1(modm1)

x≡a2(modm2)

......

x≡an(modmn)

我们假设已经找出了一些N,满足

Ni能被m1,m2,....mi-1,mi+1,mi+2....mn整除,且Ni mod mi=1,那么问题就与引例一样了,

最后的一个可行解ans=N1*a1+N2*a2+.....+Nn*an

现在问题的关键在于如何找出这样的N

设M=m1*m2*...*mn,x,y为任意整数,由N的含义可知

Ni=M/mi*x

Ni=mi*y+1

转化为M/mi*x-mi*y=1,其中M/mi,mi均为已知,求解x,y,问题变成了我们熟悉的扩展欧几里德,由此便可求出Ni,进而求出一个可行解ans,易知通解为ans+k*M,

若求最小正整数解只需abs(ans)modM。


cogs 1786

裸的模板题

#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>using namespace std;long long n,m,shu=1;long long w[20],b[20];long long gcd(long long a,long long b,long long &x,long long &y){  long long ret,tmp;  if(!b)  {    x=1;    y=0;    return a;  }  ret=gcd(b,a%b,x,y);  tmp=x;  x=y;  y=tmp-a/b*y;  return ret;}long long china(long long w[],long long b[],long long k){  long long x,y,a=0,m;  for(int i=1;i<=k;++i)    shu*=w[i];  for(int i=1;i<=k;++i)  {    m=shu/w[i];    long long s=gcd(w[i],m,x,y);    a=(a+y*m*b[i])%shu;  }  if(a>0)    return a;  else     return a+shu;}int main(){  freopen("HanXin.in","r",stdin);  freopen("HanXin.out","w",stdout);  cin>>n>>m;  for(int i=1;i<=m;++i)    cin>>w[i]>>b[i];  long long ji=china(w,b,m),ans;  while(1)  {    if(ji+shu>n)      break;    ji+=shu;  }  if(n-ji<0)    ans=-1;  else    ans=n-ji;  cout<<ans;  //system("pause");  return 0;}



原创粉丝点击