zoukankan      html  css  js  c++  java
  • GCD 及 EXGCD 复习笔记

    GCD

    辗转相除法

    证明

    设实数 (a)(b) ,我们要证明 $$gcd(a,b) == gcd(b,a % b) $$

    1. 证明 $gcd(a,b) | (a-b) $

      可以发现,(a==km)(b==lm)((a-b)==(k-l)m quad(m in N^*))

      (gcd(a,b)==m),易知 $gcd(a,b) | (a-b) $ 。

      同理

      (a-b=kp)(b=lp) ,那么 (a=(k+l)p) ,所以 (gcd(a-b,b)|a)

    2. 由 $ 1 $ 可得,(gcd(a,b))(b,a-b) 的公因数,且 (gcd(a-b,b))(a,b) 的公因数。由 (gcd) 的定义可知 (gcd(a,b) leq gcd(b,a-b))(gcd(a,b) geq gcd(b,a-b))(gcd(a,b) == gcd(b,a-b))

    3. (a) 重复减去 (b) 其实就是 取模。

    Code

    很简单,直接贴了。

    int gcd(int a,int b){
       return b==0?a:gcd(b,a%b);
    }
    
    • 注意 (gcd) 只能处理正数,负数处理方法见线性同余方程。

    • 顺带一提,(lcm)(最小公倍数) ( imes gcd = a imes b)

    luogu P1029

    EXGCD

    原理要用到 (gcd) ,但用处和 (gcd) 关联其实不是很大。

    裴蜀定理

    方程

    [ax+by=gcd(a,b) ]

    至少有一组整数解。

    证明

    不难看出问题可以简化成:

    [ax+by=gcd(a,b) iff mx+ny=1 ]

    其中,(m)(n) 互质。即证明两个互质的数可以线性组合出 (1)

    (gcd) 的过程我们发现,辗转相除的实质就是更相减损,即用两数加减组合。即两个互质的数可以组合出 (1) (也就是任何数)。

    exgcd

    根据裴蜀定理,我们知道,对于一个二元一次方程:

    [ax+by=c ]

    (c)(gcd(a,b)) 的整数倍时,方程有整数解。

    那么如何解这个方程呢?

    原理

    (gcd(a,b)|c) 时 ,我们将等式两边同除以 (frac{c}{gcd(a,b)})

    [ax+by=c iff a imes frac{x}{c}+b imesfrac{y}{c}=gcd(a,b) ]

    (frac{x}{c})(frac{y}{c})(x')(y'),根据 (gcd) 的原理我们知道:

    [b imes x''+a\%b imes y''= gcd(b,a\% b)\ implies b imes x''+(a-b imes lfloorfrac{a}{b} floor) imes y''=gcd(b,a\%b)\ implies a imes y''+b imes (x''-lfloorfrac{a}{b} floor imes y'')=gcd(b,a\%b)=gcd(a,b)\ implies a imes y''+b imes (x''-lfloorfrac{a}{b} floor imes y'')=ax'+by' \ herefore x'=y''qquad y'=x''-lfloorfrac{a}{b} floor imes y'' ]

    这样不断递归下去,直到:

    [gcd(a,b) imes x'''+0 imes y'''=gcd(a,b)\ herefore x'''=1qquad y'''=0 ]

    然后回溯回去求得 (x)(y)

    Code

    void exgcd(int a,int b,int &x,int &y){
    	if(b==0){
    		x=1;y=0;
    	}
    	else{
    		exgcd(b,a%b,y,x);
    		y-=(a/b)*x;
    	}
    }
    

    线性同余方程*

    母题

    求解

    [ax equiv b (mod p) ]

    原式可以如下变换:

    [(a imes x)\%p=b\%p iff (a imes x-b)\%p=0\ implies ax+b=py \ implies ax+p(-y)=b ]

    这样我们就能用 (exgcd) 求解了。

    这里要注意,(exgcd) 求解的是

    [ax+p(-y)=gcd(a,p) ]

    我们要给求出的解进行处理才行。

    下面我们来上题

    例题

    luogu P1082 MOD

    模板啦直接贴代码

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    
    void exgcd(int a,int b,int &x,int &y){
    	if(b==0){
    		x=1;
    		y=0;
    	}
    	else{
    		exgcd(b,a%b,y,x);
    		y-=(a/b)*x;
    	}
    }
    
    int main()
    {
    	int a,b;
    	int x,y;
    	scanf("%d %d",&a,&b);
    	//a,b互质 
    	exgcd(a,b,x,y);
    	printf("%d",((x%b)+b)%b);
    	return 0;
    }
    

    [luogu P1516] 青蛙ha的约会

    1. 题目大意:

    求满足 (x+k imes n equiv y+k imes m quad (mod ; l)) 的最小的 (k)

    1. 推柿子:

    [(x+k imes n )\%l = (y+k imes m)\%l\ implies (x-y)+(n-m) imes k=l imes lambda\ implies (m-n) imes k+l imes lambda=x-y ]

    然后几乎就转化成裸题辽。

    1. 细节

    我们发现 (m-n) 可能是负数,但是 (exgcd) 只能处理正数,所以要小小变换一下。因为我们只需要知道 (k) ,就可以这样:

    [(m-n) imes k+l imes lambda=x-y iff (n-m) imes k+l imes (-lambda)=y-x ]

    1. (Code)
    #include<cstdio>
    #include<algorithm>
    typedef int int_;
    #define int long long
    using namespace std;
    
    int n,m,wa,wb,l;
    
    int mod(int o,int p){
    	return ((o%p)+p)%p;
    }
    
    int gcd(int a,int b){
    	return b==0?a:gcd(b,a%b);
    }
    
    void exgcd(int a,int b,int &x,int &y){
    	if(b==0){
    		x=1;y=0;
    	}
    	else{
    		exgcd(b,a%b,y,x);
    		y-=(a/b)*x;
    	}
    }
    
    
    
    int_ main()
    {
    	scanf("%lld %lld %lld %lld %lld",&wa,&wb,&n,&m,&l);
    	wa=mod(wa,l);wb=mod(wb,l);
    	int a=m-n,b=l,c=wa-wb;
        if(a<0){
        	a=-a;
        	c=-c;
    	}
    	int g=gcd(a,b);
    	if(c%g != 0){
    		printf("Impossible");
    		return 0;
    	}
    	a/=g;b/=g;c/=g;
    	int x,y;
    	exgcd(a,b,x,y);
    	x*=c;
    	x=mod(x,b);
    	printf("%lld",x);
    	return 0;
    }
    

    [luogu P2421] 荒岛野人

    1. 题目大意

    和上题稍有不同,这题是两两求(c_i+k imes p_i equiv c_j+k imes p_jquad (mod; M))(min(l_i,l_j)) 内无正整数解。

    1. 做法

    很简单,只需从小到大枚举(M) ,然后检验每两个人都不会相遇就ok。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 1000000
    
    int n,maxx,c[20],p[20],l[20];
    
    int mod(int o,int M){
    	return ((o%M)+M)%M;
    }
    
    int gcd(int a,int b){
    	return b==0?a:gcd(b,a%b);
    }
    
    void exgcd(int a,int b,int &x,int &y){
    	if(b==0){
    		x=1,y=0;
    	}
    	else{
    		exgcd(b,a%b,y,x);
    		y-=(a/b)*x;
    	}
    }
    
    bool work(int i,int j,int m){
    	int a=p[i]-p[j],b=m,d=c[j]-c[i];
    	if(a<0){
    		a=-a,d=-d;
    	}
    	int g=gcd(a,b);
    	if(d%g != 0){
    		return false;
    	}
    	a/=g,b/=g,d/=g;
    	int x,y;
    	exgcd(a,b,x,y);
    	x*=d;
    	x=mod(x,b);
    	if(x <= min(l[i],l[j])) return true;
    	else return false;
    }
    
    bool check(int m){
    	for(int i=1;i<n;i++){
    		for(int j=i+1;j<=n;j++){
    			if(work(i,j,m)){
    				return false;
    			}
    		}
    	}
    	return true;
    }
    
    
    
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d %d %d",&c[i],&p[i],&l[i]);
    		maxx=max(maxx,c[i]);
    		c[i]--;
    	}
    	for(int i=1;i<=maxn;i++){
    		if(check(i)){
    			printf("%d",max(maxx,i));
    			return 0;
    		}
    	}
    	return 0;
    }
    

    内容采用“知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议”进行许可。请您在转载时注明来源及链接。


    • (frak byquad thorn\_)
  • 相关阅读:
    Educational Codeforces Round 88 (Rated for Div. 2) D. Yet Another Yet Another Task(枚举/最大连续子序列)
    Educational Codeforces Round 88 (Rated for Div. 2) A. Berland Poker(数学)
    Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability(数论)
    Educational Codeforces Round 88 (Rated for Div. 2) C. Mixing Water(数学/二分)
    Codeforces Round #644 (Div. 3)
    Educational Codeforces Round 76 (Rated for Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    Educational Codeforces Round 87 (Rated for Div. 2)
    AtCoder Beginner Contest 168
    Codeforces Round #643 (Div. 2)
  • 原文地址:https://www.cnblogs.com/thornblog/p/11715805.html
Copyright © 2011-2022 走看看