【数论】求逆元的几种方式
逆元在数论中同余方程的很多地方都会用到,这里我们来整理一下求逆元的几种方式(*・ω< )
>>>>方法介绍
【方式一】费马小定理
费马小定理:ap-1Ξ1 (mod p) 前提:p是质数且gcd(a,p)=1
则有ap-2 *a Ξ 1 (mod p)
由逆元的意义可知:a与x相乘,若在mod p的意义下与1同余,那么x是a在模p意义下的逆元
所以ap-2 是a在模p意义下的逆元
用快速幂求ap-2即可
【方式二】扩展欧几里得
费马小定理解决的范围仅为 p是质数且gcd(a,p)=1
用扩展欧几里得做法可以算是通解
设y为我们已知的数,x为y的逆元,由逆元的定义可知:x*y Ξ 1 (mod p)
用扩展欧几里得展开,得到x*y+t*p =1
注意:求得的解x还要除以gcd(y,p),即除去同时扩大的倍数
下面有一道例题大家可以练练手
【方式三】递推
递推的方法相较前两个方法来说不常使用,在这里我们只给结论
我才不会说是因为我不会证明呢(逃
inv[i]=(-p/i*inv[p%i]%p+p)%p
inv[i]就是 i 的逆元
>>>>扩展欧几里得求逆元的例题
【题目】
Mr. Hu 又来让你帮忙解方程了。
方程是这样的:x1 + x1 + x3 + · · · + xn = m (xi ≥ 0 ∀1 ≤ i ≤ n)
Mr. Hu 希望你求出这个 n 元一次方程的整数解有多少个,因为解的个数有可能变得很大,所以 Mr. Hu只需要你输出解的个数取模于 mod。
【输入格式】
第 1 行,包含一个整数:T,表示询问个数
接下来 T 行,每行包含三个整数:n m mod
【输出格式】
输出 T 行,每行输出解的个数模对应 mod
【输入样例】
1
2 3 13
【输出样例】
4
【数据范围及约定】
样例中,解分别是:(3, 0),(2, 1),(1, 2),(0, 3)
• 对于 30% 的数据,1 ≤ n, m ≤ 6,mod = 108 + 7,T = 1
• 对于 70% 的数据,1 ≤ n, m ≤ 103,n + m ≤ mod ≤ 108 + 7,mod 是一个素数,1 ≤ T ≤ 100
• 对于余下 30% 的数据,1 ≤ n, m ≤ 103,n + m ≤ p, q ≤ 104,mod = p*q,p, q 是素数,1 ≤ T ≤ 103
>>>>分析
把每一个数的位置看做一个盒子,一共n个。把m看成m个球
问题等价于:“将m个球放进n个盒子,盒子可以为空”(解可以为0)的方案数
我们考虑使用隔板法,在这里介绍一下
题目:将5个完全相同的小球放入3个不同的盒子,盒子可以为空,一共有多少种放法?
解析:将5个小球放入3个盒子,需要2个隔板(分成三个区间,每个区间对应一个盒子)
因为允许有盒子为空,不符合隔板法的原理,那我们就再加上3个小球,保证每个盒子都至少分到一个小球(分完后再减去)
然后题目就变成了8个完全相同的小球放入三个不同的盒子,不可以为空。
8个球里一共有7个空位(两个球之间一个空位)需要在这7个空位里加入两个隔板来分隔成三个区间,那么一共有C(7,2)种不同的放法
那么这道题最终要求的就是C(n+m-1,n-1)
组合数的公式是C(m,n)=n!/((n-m)!*m!)将n!与m!约分,即为求(m+1)*(m+2)*....*n
原式转化为C(m,n)=(m+1)*(m+2)*....*n/(n-m)!
那么我们只需要用扩展欧几里得求出(n-m)!就可以了
代码如下
>>>>代码
#include<bits/stdc++.h> #define ll long long #define L I64 using namespace std; int T; ll p; ll exgcd(ll a,ll &x,ll b,ll &y) { if(b==0) { x=1,y=0; return a; } ll xx,yy,d=exgcd(b,xx,a%b,yy); x=yy; y=xx-a/b*yy; return d; } ll C(ll m,ll n) { ll jcn=1,jcm=1; for(int i=m+1;i<=n;i++) jcm=jcm*i%p; for(ll i=1;i<=n-m;i++) jcn=jcn*i%p; ll x,y,gcd=exgcd(jcn,x,p,y); x=x/gcd; return (jcm*x%p+p)%p; } ll n,m; int main() { // freopen("eqution.in","r",stdin); // freopen("eqution.out","w",stdout); scanf("%d",&T); while(T--) { scanf("%Ld%Ld%Ld",&n,&m,&p); printf("%Ld ",C(n-1,n+m-1)); } return 0; }
完结撒花✿✿ヽ(°▽°)ノ✿
感谢 被称为std的sxk大佬的思路!