求逆元的方法汇总

来源:互联网 发布:假人挑战是什么软件 编辑:程序博客网 时间:2024/05/22 08:17

求逆元的方法汇总

  • 源于PO姐在UOJ群里面的讲课%%%%%

逆元

它是一个可以取消另一给定元素运算的元素。
amax1(mod  m)xam

前提

a(modm),am,

定理

欧拉定理(费马小定理)

  • 欧拉定理:amaφ(m)1(mod  m)

方法

1.欧拉定理

根据欧拉定理

aϕ(m)aaϕ(m)1a111aϕ(m)1(modm)(modm)(modm)

所以aϕ(m)1a
时间复杂度O(n)即求出单个欧拉函数的值

2.exgcd

应用exgcd
我们假设a的逆元是x

axax+my=11(modm)

用exgcd求出x即为a的逆元
时间复杂度O(loga)

3.需要线性处理1~n的逆元

更正:本方法需在模数为素数情况下才能使用!!!
我们假设y=ax+b, b<i, 1<x<y
在将这个式子放在mody 意义下

ax+b0(mody)

两边同时乘上x1b1得到
ab1+x1x10ab1(mody)(mody)

再将y=ax+b带入得到
x1yx(ymodx)1(mody)

所以我们定义a[i]xmody意义下的逆元,根据上式得到
a[i]=(y  div  x)a[ymodx]
1在模任何意义下逆元都是1
同时也就得到了一种O(logN)级别的递归求单个逆元的方法
由于每次取模,所以每次都相当于折半,复杂度就降到了O(logN)

最后贴上代码

1.欧拉定理

const    maxn=1000;var    prime:array[0..maxn]of longint;    check:array[0..maxn]of boolean;    i,j,k:longint;    n,m,tt,len,ans:longint;procedure prepare;begin    len:=0;    for i:=2 to trunc(sqrt(maxn)) do        begin            if check[i]=false            then begin inc(len); prime[len]:=i; end;            for j:=1 to len do                begin                    if prime[j]*i>trunc(sqrt(maxn)) then break;                    check[i*prime[j]]:=true;                    if i mod prime[j]=0 then break;                end;        end;end;function f(a,b,m:longint):longint; {a^b mod m}var t,y:int64;begin    t:=1; y:=a;    while b<>0 do        begin            if b and 1<>0 then t:=(t*y)mod m;            y:=(y*y)mod m;            b:=b>>1;        end;    exit(t);end;begin    prepare;    readln(n,m); tt:=m;    ans:=m;    for i:=1 to len do        begin            if m=1 then break;            if m mod prime[i]=0 then ans:=(ans div prime[i])*(prime[i]-1);            while m mod prime[i]=0 do                m:=m div prime[i];        end;    if m<>1 then ans:=(ans div m)*(m-1);    writeln(f(n,ans-1,tt));end.

2.exgcd

var    n,m,a,b,c,x,y:longint;procedure exgcd(a,b:longint; var x,y:longint);var c:longint;begin    if b=0    then begin x:=1; y:=0; exit; end    else exgcd(b,a mod b,x,y);    c:=x; x:=y; y:=c-(a div b)*x;end;begin    readln(n,m);    exgcd(n,m,x,y);    x:=(x+((x div m)+1)*m+m)mod m;    writeln(x);end.

线性处理1~n

const    maxn=1000;var    x:array[0..maxn]of longint;    i,j,k:longint;    n,m:longint;begin    readln(n,m);    x[1]:=1;    for i:=2 to n do        x[i]:=(-(m div i)*x[m mod i])mod m;    writeln(x[i]);end.    

线性处理转求单个

var    n,m:longint;function f(a:longint):longint;begin    if a=1    then exit(1)    else exit((-(m div a)*f(m mod a))mod m);end;begin    readln(n,m);    writeln(f(n));end.
0 0
原创粉丝点击