蓝书
同余方程组:形如$x equiv a_i(mod\,m_i)$的n个方程(各个$m_i$两两互质;好像$m_i=1$时以下一些会不成立?然而不要紧)
令$M=prod_{i=1}^n m_i$
令$w_i=M/m_i$
根据各个$m_i$两两互质,可得$w_i$与$m_i$互质
找出$p_i$等于$w_i$关于$m_i$的乘法逆元;则$p_i*w_i equiv 1(mod\,m_i)$
令$x_0=sum_{i=1}^n a_i*p_i*w_i$
显然,对于第i个方程,$x_0 equiv a_i*p_i*w_i equiv a_i(mod\,m_i)$(因为对于$j!=i$,$w_j equiv 0(mod\,m_i)$)
得到了一组可行解;则任意解即为$x_0+k*M$,k为任意整数
扩展
各数不互质?
换一种方法:两两合并
现在已知形如$x equiv a_i(mod\,m_i)$的2个方程,$m_i$不需要互质
设$x=k_1*m_1+a_1$,$x=(-k_2)*m_2+a_2$
那么$k_1*m_1+k_2*m_2=a_2-a_1$
可以用exgcd解出一组合法的$k_1$和$k_2$(当然没有合法解就不存在方程组的解)
因此$x equiv k_1*m_1+a_1(mod\,lcm(m_1,m_2))$
弃用
用exgcd找出每个$p_i$,使得$p_i*w_i+q_i*m_i=1$(实际上就是$p_i$是$w_i$关于$m_i$的乘法逆元)
那么两边模$m_i$,得到$p_i*w_i equiv 1(mod\,m_i)$(因为$p_i$,$w_i$都显然不为$m_i$的倍数)
例题
Strange Way to Express Integers POJ - 2891
错误记录:
32行k1也要取模,根据exgcd的解的通式,取模的对象是m[i]/g
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pi; 13 //xa+yb=1 14 void exgcd(ll a,ll b,ll &g,ll &x,ll &y) 15 { 16 if(!b) {x=1;y=0;g=a;} 17 else {exgcd(b,a%b,g,y,x);y-=x*(a/b);} 18 } 19 ll Mod(ll a,ll b) 20 { 21 if(a>=0) return a%b; 22 else if(a%b==0) return 0; 23 else return b+a%b; 24 } 25 ll ex_china(ll n,ll *a,ll *m) 26 { 27 ll i,k1,k2,g,lm=m[0],la=Mod(a[0],m[0]),t; 28 for(i=1;i<n;i++) 29 { 30 exgcd(lm,m[i],g,k1,k2); 31 if((a[i]-la)%g!=0) return -1; 32 t=m[i]/g;k1=Mod(k1*((a[i]-la)/g),t);t*=lm; 33 la=Mod(k1*lm+la,t);lm=t; 34 } 35 return la; 36 } 37 ll n,a[100100],m[100100]; 38 int main() 39 { 40 ll i; 41 while(scanf("%lld",&n)==1) 42 { 43 for(i=0;i<n;i++) scanf("%lld%lld",&m[i],&a[i]); 44 printf("%lld ",ex_china(n,a,m)); 45 } 46 return 0; 47 }