zoukankan      html  css  js  c++  java
  • 中国剩余定理/扩展中国剩余定理 学习笔记

    一、中国剩余定理(CRT)

    中国剩余定理是用来求解形如:

    [egin{cases} xequiv a_1pmod {m_1}\ xequiv a_2pmod {m_2}\ dots\ xequiv a_kpmod {m_k}\ end{cases} ]

    的方程组的定理,要求(m_1,m_2,dots m_k)两两互质。

    定理如下:

    (M=prod_{i=1}^{k}m_i,M_i=frac{M}{m_i},M_it_iequiv 1pmod m_i)

    那么一个满足以上方程组的解就是(x_0=sum_{i=1}^{k}a_iM_it_i),方程的通解即为(x=x_0+pM,pin Z)

    证明:

    对于任意(jin [1,k]),当(j ot= i)时,式子中的项(a_iM_it_iequiv 0pmod {m_j}),当(i=j)(M_jt_jequiv 1pmod{m_j}),因此(a_jM_jt_jequiv a_jpmod {m_j}) ,因此有(sum_{i=1}^{k}a_iM_it_iequiv a_jpmod {m_j}),得证。

    • 例题:洛谷模板题

      sol:每个条件就相当于(xequiv b_ipmod {a_i}),于是上模板即可,注意不能直接用费马小定理求逆元(只能在模数是质数的时候用),要用扩欧。

      code:

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N=11;
      int n,a[N],b[N];
      ll M=1;
      inline void exgcd(ll a,ll b,ll &x,ll &y){
      	if(!b){x=1;y=0;return ;}
      	exgcd(b,a%b,x,y);
      	ll t=x;x=y;y=t-a/b*y;
      }
      inline int inv(ll a,ll mod){
      	ll x,y;
      	exgcd(a,mod,x,y);
      	return (x%mod+mod)%mod;
      }
      int main(){
      	scanf("%d",&n);
      	ll ans=0;
      	for(int i=1;i<=n;++i){
      		scanf("%d%d",&a[i],&b[i]);
      		M*=a[i];	
      	}
      	for(int i=1;i<=n;++i){
      		ll mi=M/a[i],t=inv(mi,a[i]);
      		ans=(ans+mi*t%M*b[i]%M)%M;
      	}
      	printf("%lld
      ",ans);
      	return 0;
      }
      
    • 例题:洛谷P3868

      sol:(b_i|(n-a_i))意味着(nequiv a_ipmod {b_i}),于是就是模板了。注意乘法会爆(long long),于是这里使用了(mathcal O(1))快速乘。

      code:

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N=11;
      int n,a[N],b[N];
      ll M=1;
      inline void exgcd(ll a,ll b,ll &x,ll &y){
      	if(!b){x=1;y=0;return ;}
      	exgcd(b,a%b,x,y);
      	ll t=x;x=y;y=t-a/b*y;
      }
      inline ll inv(ll a,ll mod){
      	ll x,y;
      	exgcd(a,mod,x,y);
      	return (x%mod+mod)%mod;
      }
      inline ll mul(ll x,ll y,ll mod){
      	return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
      }
      int main(){
      	scanf("%d",&n);
      	ll ans=0;
      	for(int i=1;i<=n;++i)
      		scanf("%d",&a[i]);
      	for(int i=1;i<=n;++i){
      		scanf("%d",&b[i]);
      		M*=b[i];	
      	}
      	for(int i=1;i<=n;++i){
      		ll mi=M/b[i],t=inv(mi,b[i]);
      		ans=(ans+mul(mul(mi,t,M),a[i],M))%M;
      	}
      	printf("%lld
      ",ans);
      	return 0;
      }
      

    二、扩展中国剩余定理(exCRT)

    还是上面那个问题,但现在,我们不保证(m_i)互质了,这该怎么做?

    考虑递归求解,假设我们已经求出了前(i-1)个方程的解为(xequiv x_0pmod M),其中(M=lcm(m_1,m_2,dots,m_{i-1})),那么现在我们需要求解:

    [egin{cases} xequiv x_0pmod M\ xequiv a_ipmod {m_i} end{cases} ]

    那么(x=x_0+tM,tin Z)

    于是(x_0+tMequiv a_ipmod {m_i}),即(tMequiv a_i-x_0pmod {m_i}),这是同余方程的形式,于是我们直接扩展欧几里得求出(t),进而得到(x),然后更新(M),继续递归求解。总复杂度是(mathcal O(nlog(n)))的,稍逊于(CRT),注意求解过程中如果有任何一个同余方程无解,那么方程组就无解。

    • 例题:洛谷模板题

      这道模板题保证了有解,但乘法运算可能会爆(long long),依然要使用快速乘。

      code:

      #include<bits/stdc++.h>
      using namespace std;
      typedef long long ll;
      const int N=1e5+10;
      int n;
      ll M=0,a[N],m[N];
      inline void exgcd(ll a,ll b,ll &x,ll &y){
      	if(!b){x=1;y=0;return ;}
      	exgcd(b,a%b,x,y);
      	ll t=x;x=y;y=t-a/b*y;
      }
      inline ll mul(ll x,ll y,ll mod){
      	return (x*y-(ll)((long double)x/mod*y)*mod+mod)%mod;
      }
      inline ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}
      inline ll lcm(ll x,ll y){return x/gcd(x,y)*y;}
      inline void exCRT(ll a,ll b,ll &x,ll &y,ll c,ll mod){
      	ll g=gcd(a,b),t=c/g;
      	exgcd(a,b,x,y);
      	x=mul(x,t,mod),y=mul(y,t,mod);
      }
      int main(){
      	scanf("%d",&n);
      	ll ans=0;
      	for(int i=1;i<=n;++i){
      		scanf("%lld%lld",&m[i],&a[i]);
      		if(!M) M=m[1],ans=a[1];
      		else{
      			ll nM=lcm(M,m[i]),x,y;
      			exCRT(M,m[i],x,y,(a[i]-ans+nM)%nM,nM);
      			ans=(mul(M,x,nM)+ans)%nM;
      			M=nM;
      		}
      	}
      	printf("%lld
      ",ans);
      	return 0;
      }
      
  • 相关阅读:
    对Request.Url片段解析
    Php学习之路四
    解析bmp图像(某年全国软件大赛题目)
    工信部软件大赛(解析bmp)
    Php学习之路三(字符串操作)
    C++二维数组做形参
    php学习之路五(表单验证)
    PHP(学习之路一)
    PHp学习之路二(数组练习)
    解析网页(KMP算法实现部分)
  • 原文地址:https://www.cnblogs.com/tqxboomzero/p/14359160.html
Copyright © 2011-2022 走看看