-
快速幂
-
扩展欧几里得
-
baby-step-giant-step
可以自行baidu
程序附部分注释
1 const key=1000007; 2 type link=^node; 3 node=record 4 re,wh:longint; 5 next:link; 6 end; 7 8 var hash:array[0..key] of link; 9 a:array[0..100] of longint; 10 j,g,ans,w,i,n,ch,t,p,z,y:longint; 11 x,step,k,now:int64; 12 13 function quick(y,z,p:longint):int64; 14 var t,i:longint; 15 begin 16 quick:=1; 17 t:=0; 18 while z<>0 do 19 begin 20 inc(t); 21 a[t]:=z mod 2; 22 z:=z div 2; 23 end; 24 for i:=t downto 1 do 25 begin 26 quick:=sqr(quick) mod p; 27 if a[i]=1 then quick:=quick*y mod p; 28 end; 29 end; 30 31 function gcd(a,b:longint):longint; 32 begin 33 if b=0 then exit(a) 34 else exit(gcd(b,a mod b)); 35 end; 36 37 procedure exgcd(a,b:longint;var x,y:int64); //扩展欧几里得 38 var xx,yy:int64; 39 begin 40 if b=0 then 41 begin 42 x:=1; 43 y:=0; 44 end 45 else begin 46 exgcd(b,a mod b,x,y); 47 xx:=x; 48 yy:=y; 49 x:=yy; 50 y:=xx-(a div b)*yy; 51 end; 52 end; 53 54 procedure add(x,i:longint); 55 var p:link; 56 begin 57 w:=x mod key; 58 p:=hash[w]; 59 while p<>nil do 60 begin 61 if p^.re=x then break; 62 p:=p^.next; 63 end; 64 if p=nil then 65 begin 66 new(p); 67 p^.re:=x; 68 p^.wh:=i; 69 p^.next:=hash[w]; 70 hash[w]:=p; 71 end; 72 end; 73 74 function find(x:longint):longint; 75 var p:link; 76 begin 77 find:=-1; 78 w:=x mod key; 79 p:=hash[w]; 80 while p<>nil do 81 begin 82 if p^.re=x then exit(p^.wh); 83 p:=p^.next; 84 end; 85 end; 86 87 begin 88 readln(n,ch); 89 for i:=1 to n do 90 begin 91 readln(y,z,p); 92 if ch=1 then 93 writeln(quick(y,z,p)) //快速幂不多说 94 else if ch=2 then 95 begin 96 g:=gcd(y,p); 97 if z mod g<>0 then //先判断线性模方程是否有解 98 begin 99 writeln('Orz, I cannot find x!'); 100 continue; 101 end; 102 y:=y div g; 103 p:=p div g; 104 z:=z div g; 105 exgcd(y,p,x,k); //转化为二元一次不定方程 106 x:=((x*z mod p)+p) mod p; //注意是最小非负数 107 writeln(x); 108 end 109 else begin 110 z:=z mod p; 111 t:=trunc(sqrt(p))+1; 当t选址为根号p时时间复杂度最优 112 for j:=0 to key do 113 hash[j]:=nil; 114 now:=1; 115 add(1,0); 116 for j:=1 to t do //求出a^i mod p(0<=i<=t) 的值,并映射到hash上,每个模保留最小的i 117 begin 118 now:=now*y mod p; 119 add(now,j); 120 end; 121 g:=gcd(now,p); 122 if g<>1 then //求出a^t关于mod p的逆元,没有逆元则无解 123 begin 124 writeln('Orz, I cannot find x!'); 125 continue; 126 end 127 else begin 128 now:=now div g; 129 w:=p div g; 130 end; 131 exgcd(now,w,x,k); 132 x:=(x+w) mod w; 133 ans:=-1; 134 step:=z; 135 for j:=0 to t-1 do 136 begin 137 k:=find(step); //大小步寻找 对于a^it ~ a^(i+1)t-1 (0<=i<=t-1) 寻找可行解 138 //存在可行解即存在hash中存在模=z*x^i mod p (x表示a^t的逆元) 139 if k>-1 then 140 begin 141 ans:=k+j*t; 142 break; 143 end; 144 step:=step*x mod p; 145 end; 146 if ans=-1 then writeln('Orz, I cannot find x!') 147 else writeln(ans); 148 end; 149 end; 150 end.