模为2的逆元是什么_乘法逆元及两道模板题详解

乘法逆元

就是

此时b就是a模p意义下的逆元,即

下面我们用inv[a]表示a模p意义下的逆元。

逆元是好东西啊

有时候我们需要算出 a/b mod p 的值,用朴素的方法,我们只能在 a 上不断加 p ,直到它能被 b 整除为止。

当 a,b,p 都很大的时候,这种方法就只能凉凉了,但如果有了逆元,我们就可以非常方便,快捷地求解。

——————某位大佬的话

所以我先讲讲逆元性质:

唯一性就不用讲了

1.积性

假如a与b互质,

2.乘变除

证明如下:

两边都乘一个

,就得到了上面的式子

至于逆元的求法,有很多,我只讲四种。

首先,是求单个逆元

1.费马小定理

当 p 为素数时:

所以

所以

就是a在模p意义下的逆元,快速幂求出

即可。

此方法的局限就是p只能是质数。

1 int ksm(intt)2 {3 if(t==1)return n%p;4 if(t%2==0)5 return ksm(t>>1)*ksm(t>>1)%p;6 else

7 return ksm(t>>1)*ksm(t>>1)*(n)%p;8 }9 intmain()10 {11 scanf("%d%d",&n,&p);12 printf("%d",ksm(p-2));13 }

2.扩展欧几里得

变一下,我们把p移到左边就成了

因为y是变量所以可以变成这样:

我们把

设成x,就变成了扩欧的标准式:

就可以瞎搞了,至于不知道怎么瞎搞的同学,可以先点这里exgcd入门以及同余基础

1 inline voidexgcd(ll a,ll b)2 {3 if(!b)4 {x=1;y=0;return;}5 exgcd(b,a%b);6 k=x;x=y;7 y=k-a/b*y;8 return;9 }10 intmain()11 {12 scanf("%d%d",&n,&p);13 exgcd(n,p);14 printf("%d",x);15 }

然后,就是求多个逆元

1.欧拉函数筛法

在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(φ(1)=1)。

——————百度百科

我们设

表示小于等于x且与x互质的正整数的个数。

通式如下:

还有欧拉函数有如下几点性质:

欧拉函数是积性函数——若m,n互质,

假如n为奇数,

假如n为质数,

欧拉函数与费马小定理有点不明不白的关系

对任何两个互质的正整数a, m(m>=2)有

这就是欧拉定理

所以类比于费马小定理的证法:

所以

所以我们要求的就是

,又因为欧拉函数是积性函数,所以把m筛一下质数就好了。

不过有更好的办法,这里就不写代码了(其实不会)

2.线性递推

证明好麻烦啊,那就不证了

反正就是设

再往

最后得出:

讲完了,现在讲题目

我要讲洛谷的两道题:

这就是模板题,直接套线性递推,就能ac了

1 intmain()2 {3 intn,m;4 read(n),read(m);5 inv[1]=1;6 for(register int i=2;i<=n;i++)7 inv[i]=(long long)(m-m/i)*inv[m%i]%m;\\加一个m是为了去负8 for(register int i=1;i<=n;i++)9 printf("%d\n",inv[i]);10 }

值得一提的是,这题扩欧卡一卡也可以过(好水)

1 long longk,x,y;2 inline void read(long long &x)3 {4 x=0;5 int f=1;6 char ch=getchar();7 while(ch'9')8 {9 if(ch=='-')10 f=-1;11 ch=getchar();12 }13 while(ch>='0'&&ch<='9')14 {15 x=x*10+ch-'0';16 ch=getchar();17 }x*=f;18 }19 inline void exgcd(int a,long longb)20 {21 if(b==0)22 {x=1;y=0;return;}23 exgcd(b,a%b);24 k=x;x=y;25 y=k-a/b*y;26 return;27 }28 intmain()29 {30 long longn,m;31 read(n),read(m);32 for(register int i=1;i<=n;i++)33 {34 exgcd(i,m);35 if(x<=0)x+=m;36 printf("%lld\n",x);37 }38 }

对了,还有一个,费马小定理算法。

得分48,a了3个,t了3个

1 inline long long ksm(int t,int i)//记得开long long不然第三个点会wa

2 {3 if(t==1)return i%m;4 if(t%2==0)5 return ksm(t>>1,i)*ksm(t>>1,i)%m;6 else

7 return ksm(t>>1,i)*ksm(t>>1,i)*(i)%m;8 }9 intmain()10 {11 long longn;12 io::begin();13 io::read(n);14 io::read(m);15 for(register int i=1;i<=n;i++)16 printf("%lld\n",ksm(m-2,i));17 }

但是我发现,去掉inline,就a了4个点,得分64.

所以给大家一个忠告,在递归函数下,inline不是一个好的卡常方法!

因为使用内联函数后虽然调用函数的开销降低了,但是有利必有弊,内联函数会导致主函数指令增多、函数体积增大等情况。

这题就这样

一看数据范围还是很吓人的,

,怕不是要打高精,后来发现不是这样,不过题解中真有高精算法,大佬!!

首先,先看我最开始引用的话,嗯,有点道理

然后解析题目发现:本题就是求b在mod p的意义下的逆元。

所以扩欧一遍过,只是读入时注意一下边读边模就好了;

1 inline void exgcd(int a,intb)2 {3 if(!b)4 {x=1;y=0;pos=a;return;}5 exgcd(b,a%b);6 k=x;x=y;7 y=k-a/b*y;8 return;9 }10 intmain()11 {12 std::cin>>a1>>b1;13 int n=0,m=0;14 for(register int i=0;i

21 {22 if(x<0)x+=mod;23 printf("%lld",(1ll*n*x)%mod);24 }25 }

最后通过这道题的大质数给大家念一首诗:苟利国家生死以

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值