zoukankan      html  css  js  c++  java
  • 中国剩余定理与扩展中国剩余定理

    中国剩余定理与扩展中国剩余定理

    概述

    中国剩余定理是同余中常用的辅助手段,常用来合并多个同余方程的解(如MTT)。其技术难度不高,代码也很短,可以在NOIP中出现。

    中国剩余定理CRT

    形式

    给定 (n) 组非负整数 (m_i, a_i) ,求解关于 (x) 的方程组的最小非负整数解。

    [egin{cases} x equiv a_1 ({ m mod} m_1) \ xequiv a_2 ({ m mod} m_2) \ ... \ x equiv a_n ({ m mod} m_n)end{cases} ]

    其中(m_i)两两互质。

    解法

    我们贪心构造和式使得每一项在模意义下不影响其他项,并且符合当前的方程,
    (M =prod^{n}_{i=1}m_i,M_i=frac{M}{m_i}),可以构造解

    [x=sum^{n}_{i=1}M_i(a_iM_i^{-1} mod m_i) ]

    可以证明解在模M 意义下唯一。

    模板题:P3868 [TJOI2009]猜数字
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7,MAXN=11;
    inline LL mult(LL a,LL b,LL mod){
    	LL ret=0;
    	while(b>0){
    		if(b&1)
    			ret=(ret+a)%mod;
    		a=(a+a)%mod;
    		b>>=1;
    	}
    	return ret;
    }
    void exgcd(LL a,LL b,LL &x,LL &y){
    	if(!b){
    		x=1;
    		y=0;
    		return;
    	}
    	exgcd(b,a%b,y,x);
    	y-=a/b*x;
    }
    inline LL inv(LL x,LL p){
    	LL a,b;
    	exgcd(x,p,a,b);
    	return (a%p+p)%p;
    }
    int N;
    LL a[MAXN],b[MAXN],M,lcm=1,ans;
    int main(){
    	scanf("%d",&N);
    	for(int i=1;i<=N;i++)
    		scanf("%lld",a+i);
    	for(int i=1;i<=N;i++){
    		scanf("%lld",b+i);
    		lcm*=b[i];
    		a[i]=(a[i]%b[i]+b[i])%b[i];
    	}
    	for(int i=1;i<=N;i++){
    		LL Mi=lcm/b[i],t=inv(Mi,b[i]);
    		ans=(ans+mult(mult(Mi,t,lcm),a[i],lcm))%lcm;
    	}
    	printf("%lld",(ans+lcm)%lcm);
    	return 0;
    }
    

    扩展中国剩余定理EXCRT

    形式

    给定 (n) 组非负整数 (m_i, a_i) ,求解关于 (x) 的方程组的最小非负整数解。

    [egin{cases} x equiv a_1 ({ m mod} m_1) \ xequiv a_2 ({ m mod} m_2) \ ... \ x equiv a_n ({ m mod} m_n)end{cases} ]

    解法

    扩展中国剩余定理的方法和中国剩余定理关系不大,我们贪心处理前(i-1)项,然后合并当前方程。
    将每个方程拆成若干个方程

    [x=a_i(mod p_{i,j}^{k_{i,j}}) ]

    其中(m_i=prod p_{i,j}^{k_{i,j}})(m_i) 的分解式。对每个质数(p),合并对应的所有方程,从而转化为模数两两互质的情形。若合并过程中出现矛盾,则原方程组无解。

    模板题:P4777 【模板】扩展中国剩余定理(EXCRT)
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int INF=1e9+7,MAXN=1e5+10;
    inline LL mult(LL a,LL b,LL mod){
    	LL ret=0;
    	while(b>0){
    		if(b&1)
    			ret=(ret+a)%mod;
    		a=(a+a)%mod;
    		b>>=1;
    	}
    	return ret;
    }
    LL exgcd(LL a,LL b,LL &x,LL &y){
    	if(!b){
    		x=1;
    		y=0;
    		return a;
    	}
    	LL ret=exgcd(b,a%b,y,x);
    	y-=a/b*x;
    	return ret;
    }
    int N;
    LL a[MAXN],b[MAXN],M,ans,x,y;
    int main(){
    	scanf("%d",&N);
    	for(int i=1;i<=N;i++){
    		scanf("%lld%lld",b+i,a+i);
    		a[i]=(a[i]%b[i]+b[i])%b[i];
    	}
    	M=b[1];
    	ans=a[1];
    	for(int i=2;i<=N;i++){
    		LL rm=(a[i]-ans%b[i]+b[i])%b[i];
    		LL gcd=exgcd(M,b[i],x,y);
    		LL bg=b[i]/gcd; 
    		/*if(rm%gcd):ERROR*/
    		x=mult(x,rm/gcd,bg);
    		ans+=x*M;
    		M*=bg;
    		ans=(ans%M+M)%M;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    JS URL传中文参数引发的乱码问题
    git (转载)
    php webservice
    php date之间的相互转换
    在图片上加字符-base64转图片-图片转base64
    转:微软面试一百题
    2014-8-17 note
    some base knowledge
    introduction
    Centos6.6 编译安装nginx
  • 原文地址:https://www.cnblogs.com/guoshaoyang/p/11296138.html
Copyright © 2011-2022 走看看