• 扩展GCD和线性模方程组


    扩展GCD即求解ax+by=c(a,b,c一般为已知整数)此类的方程所用方法。

    其精华部分就在于GCD那个函数部分。证明等详见百度百科。

    先求ax+by=GCD(a,b) 保证有解

    那么对于原方程:

    有解条件:c mod GCD(a,b)=0

    一组解:x*(c/GCD(a,b)),y*(c/GCD(a,b))。

    这样,我们就能在至多O(logn)的时间内求出一组解了。

    有一个显然的性质是:x加上b且y减去a,方程仍满足。

    那么我们要取一个对于x(或y)的最小非负整数解时,就可以这样做:

    x=(x mod b+b) mod b (b>0)

        (x mod b-b) mod b (b<0)

       即(x mod b+abs(b)) mod b

        b=0的话。。。这个就只有唯一解了。

    那么对于求解线性模方程组,用中国剩余定理的话,有一定的局限性,即模数必须两两互质,而扩展GCD就没有这个限制了。

    大致解法就是把方程合并,对于两个方程:

    X mod a=b

    X mod a'=b

    设X=ak+b=a'k'+b'

    则ak-a'k'=b'-b,a,-a',(b'-b)代入方程求出k,k'(同时判无解),然后算出X。

    这样两个方程就合并成了X mod LCM(a,a')=X 很好理解,满足这一方程的X必定能同时满足原来的两个原方程,反过来也成立。这样就合并N-1次,求出最后的余数。

    PKU1061

    var x,y,n,m,L,gg,xx,yy,zz:int64;
    function gcd(a,b:int64;var x,y:int64):int64;
    var tmp:int64;
    begin
    	if b=0 then begin gcd:=a;x:=1;y:=0;end
    	       else
    		   begin
    			gcd:=gcd(b,a mod b,x,y);
    			tmp:=x;x:=y;y:=tmp-a div b*y;
    		   end;
    end;
    
    begin
    	readln(x,y,m,n,L);
    	gg:=gcd(m-n,L,xx,yy);
    	if ((y-x) mod L) mod gg<>0 then writeln('Impossible')
    							   else
    							   begin
    								//writeln((((y-x) mod L) div gg*xx) mod L);
                                                                    zz:=(((y-x) mod L) div gg*xx) mod L;
                                                                    zz:=(zz+L) mod L;
                                                                    writeln(zz);
    							   end;
    end.
    

    线性模方程:

    var t,l,n,i:longint;gg,x,y:int64;pd:boolean;
        a,b:array[1..10] of int64;
    function gcd(a,b:int64;var x,y:int64):int64;
    var tmp:int64;
    begin
    	if b=0 then begin gcd:=a;x:=1;y:=0;end
    	       else
    		   begin
    				gcd:=gcd(b,a mod b,x,y);
    				tmp:=x;x:=y;y:=tmp-a div b*y;
    		   end;
    end;
    
    begin
    	readln(t);
    	for l:=1 to t do
    	begin
    		readln(n);
    		for i:=1 to n do read(a[i]);readln;
    		for i:=1 to n do read(b[i]);readln;
    		pd:=true;
    		for i:=2 to n do
    		begin
    			gg:=gcd(a[i-1],-a[i],x,y);
    			if (b[i]-b[i-1]) mod gg<>0 then begin pd:=false;break;end;
                            b[i]:=x*((b[i]-b[i-1]) div gg)*a[i-1]+b[i-1];
    			a[i]:=a[i-1]*a[i] div abs(gg);
                            b[i]:=(b[i] mod a[i]+a[i]) mod a[i];
    		end;
                    write('Case ',l,': ');
    		if pd then if b[n]=0 then writeln(a[n]) else writeln(b[n])
    		      else writeln(-1);
    		
    	end;
    end.
    
  • 相关阅读:
    正则表达式基础学习
    二识angularJS
    元素的居中方式总结
    初识AngularJs
    初识Vue.js
    Flight学习(一)
    Servlet/JSP-07 Session应用
    Servlet/JSP-05 Cookie
    Servlet/JSP-06 Session
    Servlet/JSP-04 JSP基础
  • 原文地址:https://www.cnblogs.com/oldmanren/p/2124609.html
Copyright © 2020-2023  润新知