[POJ1845&POJ1061]扩展欧几里得应用两例

扩展欧几里得是用于求解不定方程、线性同余方程和乘法逆元的常用算法。

下面是代码:

 

 

 1 function Euclid(a,b:int64;var x,y:int64):int64;
 2 var t:int64;
 3 begin
 4     if b=0 then
 5     begin
 6         x:=1;y:=0;exit(a);
 7     end else
 8     begin
 9         Euclid:=Euclid(b,a mod b,x,y);
10         t:=x;x:=y;y:=t-(a div b)*y;
11     end;
12 end;

 

 

下面出现了其中后两个应用。(虽然个人认为不定方程和同余方程可以互相转换)


 

POJ1061 

  线性同余简单应用。

 1 program poj1061;
 2 var x0,y0,m,n,L,a,b,d,x,y,tem,c:int64;
 3 
 4 function f(a:int64):int64;
 5 begin
 6     if a<0 then a:=a+(-a) div L*L;
 7     while a<=0 do a:=a+L;
 8     exit(a);
 9 end;
10 
11 function Euclid(a,b:int64;var x,y:int64):int64;
12 var t:int64;
13 begin
14     if b=0 then
15     begin
16         x:=1;y:=0;exit(a);
17     end else
18     begin
19         Euclid:=Euclid(b,a mod b,x,y);
20         t:=x;x:=y;y:=t-(a div b)*y;
21     end;
22 end;
23 
24 begin
25     readln(x0,y0,m,n,L);
26     a:=f(m-n);b:=L;    
27     d:=Euclid(a,b,x,y);
28     c:=f(y0-x0);
29     // 由于扩展欧几里得算法里要求最大公约数,所以要处理成正数
30     // 根据同余方程的性质,a,b,c加上L对答案不会有影响。
31     if c mod d<>0 then 
32     begin
33         writeln('Impossible');
34         // 同余方程有整数解的条件。
35         halt;
36     end;
37     x:=x*c div d;
38     if x<0 then x:=x+(-x) div (b div d)*(b div d);
39     while x<0 do x:=x+(b div d);
40     //这里是保证跳的步数为自然数
41     if x-(b div d)>=0 then x:=x-x div (b div d)*(b div d);
42     while x-(b div d)>=0 do x:=x-(b div d);
43     //这里是保证跳的步数是最小步数
44     writeln(x);
45 end.


 

POJ1845

 

  由于姿势不大对...交了很多遍处理了很多细节才过。

  因此觉得这道题挺好的...因为本来觉得只是一道求逆元的模板题,但实际上想要A掉它并不容易。

  首先先讲一下算法部分。

  求a^b的约数和。

  = (p1^0+p1^1+...p1^k1)*(p2^0+p2^1...+p2^k2)...*(pn^0+pn^1+...pn*kn) (p为a的质因子,ki为第i个质因子的个数)

  我们可以用素数拆分,然后对于每一部分,用等比数列求和公式。

  分子部分可以用取模的快速幂解决。

  分母部分乘上其逆元。

  大体的思路已经构建好了。

  但是细节超级超级多.....>_< 已经被搞疯啦...直接在代码里贴出来好了。

 


 

 1 program poj1845;
 2 const tt=9901;
 3 var a,b,ans,k:int64;
 4       i:longint;
 5 
 6 function Euclid(a,b:int64;var x,y:int64):int64;
 7 var t:int64;
 8 begin
 9     if b=0 then
10     begin
11         x:=1;y:=0;exit(a);
12     end else
13     begin
14         Euclid:=Euclid(b,a mod b,x,y);
15         t:=x;x:=y;y:=t-(a div b)*y;
16     end;
17 end;
18 
19 function mul(a,b:int64):int64;
20 var ans,w:int64;
21 begin
22     ans:=1;w:=a mod tt;
23     while b>0 do 
24     begin
25         if b and 1=1 then ans:=(ans*w)mod tt;
26         w:=(w*w) mod tt;
27         b:=b >> 1;
28     end;
29     exit(ans);
30 end;
31 
32 function inverse(p:int64):int64;
33 var x,y:int64;
34 begin
35     if Euclid(p,tt,x,y)<>1 then exit(-1) else
36     begin
37         while x<tt do inc(x,tt);            
38         x:=x mod tt;
39         // 我们需要找到一个正的逆元,根据x= x0+b/d*t可以得到,d=1,b=tt。所以只要不停加上tt即可。
40         // 虽然刚开始的直觉就是不停加上tt直到找到一个正的为止...但是实际上是有理论依据的。
41         exit(x);
42     end;
43 end;
44     
45 begin
46     while not eof do 
47     // 由于被多组数据坑过...所以不管怎样还是加上为好
48     begin
49         readln(a,b);
50         if a=0 then 
51         begin
52             writeln(0);
53             // 这是一个细节需要特判
54             continue;
55         end;        
56         ans:=1;
57         for i:=2 to trunc(sqrt(a)) do if a mod i=0 then 
58         begin
59             k:=0;
60             while a mod i=0 do 
61             begin
62                 inc(k);a:=a div i;
63             end; 
64             k:=k*b;
65             ans:=((ans*((mul(i,k+1)+tt-1) mod tt)) mod tt*inverse(i-1))mod tt;
66             // 本来这里的inverse(i-1)也需要处理i mod tt=1的情况,但是由于数据范围i的上限正好是7000多不用考虑。
67     end;
68     // 刚开始下面的一块都忘了QAQ
69         if a<>1 then 
70         begin
71             if a mod tt=1 then 
72             begin
73                 ans:=ans*(b+1) mod tt;            
74             // 这是最容易忽略的一个细节。当a mod tt=1的时候,inverse(i)是算不出来的,这个时候思考一下便发现,a mod tt=1
75             // a^k mod tt=1,所以最后mod tt余数就是b+1.
76             // 刚开始由于直接输出了(b+1) WA了一次...后来发现剩下的a不一定是a本身。
77         end else
78             begin
79                 i:=a;k:=b;        
80                 ans:=((ans*((mul(i,k+1)+tt-1) mod tt)) mod tt*inverse(i-1)) mod tt;
81             end;
82         end;    
83         writeln(ans);
84     end;
85 end.
86         

 

posted @ 2015-03-27 14:29  mjy0724  阅读(186)  评论(0编辑  收藏  举报