hdu 1576 A/B 求逆元模板题

来源:互联网 发布:gcr.io 阿里云 编辑:程序博客网 时间:2024/06/08 15:41

一些基本概念:

乘法逆元,是指数学领域群G中任意一个元素a,都在G中有唯一的逆元a‘,具有性质a×a'=a'×a=e,其中e为该群的单位元。

 

用[a]n代表x%n=a.的所有满足条件的x所组成的集合,其中a为集合中最小非负整数,用最小的非负整数来代表整个集合,即[a]n={a+k*n,k∈Z)

Zn={ [0]n, [1]n ,[2]n ,[3]n ,…, [n-1]n }

在模n乘法群(Zn*,  *)中,Zn*={[a]n∈Zn,且gcd(a,n)=1},单位元为[1]n,不在群里的元素没有关于模n的逆元,若某个[a]n有逆元x,那么[a]n *  [ x ]n===1(mod n)(一个元素与其对应的逆元进行运算结果为单位元),转换为ax+ny=1,an关于整数x,y线性组合,故gcd(a,n)=ax+ny=1.

所以某个元素在模n乘法运算下存在逆元,必须gcd(a,n)=1.

由存在逆元的条件gcd(a,n)=ax+ny=1.可以用exgcd求出x,这里求出的x可能不是最小非负,要将其转化为最小非负(代表元素)。另,x有无穷多个解X0=x+k*n,k∈Z,将解得的x化为代表元素,也即a的逆元。


题目思路:B是可以整除A的,且B与9973互质,说明B的模9973乘法运算存在逆元,用X表示B的逆元,那么(A/B)%9973可以转化为(n*X)%9973.所以题目要求求出X即可

B*x=1(mod)9973(x为B关于9973的逆元)   => B*x + 9973*y = 1.用扩展欧几里得算出x就是B关于模9973的逆元 (A/B)%9973 = (A*x)%9973

#include<cstdio>using namespace std;//求  (A/B)%9973  且gcd(B,9973)=1,B能整除A void exgcd(int a,int b,int d,int &x,int &y){if(!b){x=1;y=0;d=a;}else{exgcd(b,a%b,d,y,x);y-=x*(a/b);}}int main(){int n,b;int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&b);int d,x,y;exgcd(b,9973,d,x,y);x=(x%9973+9973)%9973;//解得B的逆元 int ans=(n*x)%9973;printf("%d\n",ans);}} 


费马小定理求逆元:

a^(p-1) ≡1 (mod p)  p是质数,a与p互质

两边同除以a

a^(p-2) ≡1/a (mod p) 1/a就是a关于模p的逆元。

逆元x=a^(p-2) (mod p)快速幂解出来就行了

#include<cstdio>#define ll long longusing namespace std;int pow(int a,int n,int p){int ret=1;while(n){if(n&1)ret=((ll)ret*a)%p;a=((ll)a*a)%p;n>>=1;}return ret;}int main(){int n,b;int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&b);b=pow(b,9973-2,9973);b=((b%9973)+9973)%9973;printf("%d\n",(n*b)%9973);}} 


原创粉丝点击