模运算的运算法则及逆元的计算、利用逆元计算组合数

模运算与基本四则运算有些相似,但是除法例外。其规则如下:
(a + b) % p = (a % p + b % p) % p
(a - b) % p = (a % p - b % p) % p
(a * b) % p = (a % p * b % p) % p
(a^b) % p = ((a % p)^b) % p

推论:
若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);
若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);
若a≡b (% p),c≡d (% p),则 (a + c) ≡ (b + d) (%p),(a - c) ≡ (b - d) (%p),
(a * c) ≡ (b * d) (%p),(a / c) ≡ (b / d) (%p);

对于(a÷b)%p,如果存在b1,这个b1满足的条件是,b * b1%p=1。。这样,将式子(a÷b)%p乘上b * b1%p,结果不变,式子变为(a * b1)%p。这样就将除法转换为乘法计算。这样的b1称作b模p的逆元。

怎样求逆元呢?
1.费马小定理
如果p为素数,且gcd(b,p)=1,那么就有bp-1 = 1 (modP),即b * bp-2 =1(modP),则bp-2 即为b模P的逆元。用快速幂可以实现。
费马小定理

2.扩展欧几里得求逆元
原理解释:
扩展欧几里得算法:计算乘法逆元
注意,模数P应该取比要求逆元的数大的素数,这样可以保证P与该数互质,只有满足互质前提,扩展欧几里得算法得到的x才是逆元。超全超实用的素数表
扩展欧几里得求逆元计算组合数:

public class Main {
	static InputReader sc=new InputReader(System.in);
	static int maxn=100010,p=1000000007;
	static long f[]=new long[maxn];
	public static void main(String args[]) {
		PrintWriter out=new PrintWriter(System.out);
		f[0]=1;
		for(int i=1;i<maxn;i++) {
			f[i]=f[i-1]*i%p;
		}
		out.println(C(b,a)%p);//C(n,m),n>=m.
	}
	static long C(int a,int b) {
		long A=f[b];
		long B=f[b-a]*f[a]%p;
		long C=mod_reverse(B, p);
		return A*C%p;
	}
	static class LLong{
		long v=0;
	}
	static long extend_gcd(long a,long b,LLong x,LLong y)
	{
	  if(a==0&&b==0) return -1;//无最大公约数
	  if(b==0){x.v=1;y.v=0;return a;}
	  long d=extend_gcd(b,a%b,y,x);
	  y.v-=a/b*x.v;
	  return d;
	}
	//*********求逆元素*******************
	//ax = 1(mod n)
	static long mod_reverse(long a,long n)
	{
	  LLong x=new LLong(),y=new LLong();
	  long d=extend_gcd(a,n,x,y);
	  if(d==1) return (x.v%n+n)%n;
	  else return -1;
	}
}

扩展欧几里得算法求逆元

#include <bits/stdc++.h>
using namespace std;
void ExPower( int b, int p, int & a, int & k ) {
    if( p == 0 ) {
        a = 1; k = 0;
        return;
    }
    ExPower( p, b % p, k, a );
    k -= b / p * a;
    return;
}
int main() {
    int b, p;
    cin >> b >> p;
    int a, k;
    ExPower( b, p, a, k );
    if( a < 0 ) a += p;
    cout << a << endl;
    return 0;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值