hdu 1576 A/B 求逆元模板题

一些基本概念:

乘法逆元,是指数学领域群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,a和n关于整数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 long
using 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);
	}
} 


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值