求逆元 求组合数

2019-04-13 20:58发布


求一个数a的模p(一般为质数,否则有些数求不出逆元)的逆元。 (1)
费马小定理:
费马小定理数论中的一个重要定理,其内容为: 假如p是质数,且(a,p)=1,那么 a^(p-1) ≡1(mod p)。即:假如a是整数,p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。 则a的逆元是(a%p)^(p - 1),要求p为质数,且(a,p)= 1,a为整数。注意:a>p时先取模。 欧拉定理:数论中,欧拉定理,(也称费马-欧拉定理)是一个关于同余的性质。欧拉定理表明,若n,a为正整数,且n,a互质,则:  则a的逆元是a^(p - 1),要求a和p互质,且a和p为正整数。
(2)


求组合数方法 (1)递推 (2)利用逆元和公式(一般要求mod p为质数) 。
cm(a,b) (a!/(a-b)!) / (b!) mod p  a! * inv(b!) * inv( (a - b)! ) mod p = a! * (b!*(a-b)!)^(p-2) mod p (3)利用Lucas定理(一般要求mod p为质数)。http://blog.csdn.net/wukonwukon/article/details/7341270 数论Lucas定理是用来求 c(n,m) mod p的值,p是素数(从n取m组合,模上p)。 描述为: Lucas(n,m,p)=cm(n%p,m%p)* Lucas(n/p,m/p,p) Lucas(x,0,p)=1; 而 cm(a,b)=a! * (b!*(a-b)!)^(p-2) mod p 也= (a!/(a-b)!) * (b!)^(p-2)) mod p 这里,其实就是直接求 (a!/(a-b)!) / (b!) mod p 由于 (a/b) mod p = a * b^(p-2) mod p 注:对于大组合数取模,n,m不大于10^5的话,用逆元的方法,可以解决。对于n,m大于10^5的话,那么要求p<10^5,这样就是Lucas定理了,将n,m转化到10^5以内解。
http://www.kuangbin.net/archives/lucas_theorem#more-228
http://blog.csdn.net/acm_cxlove/article/details/7844973
Lucas定理求组合数的模板:  模板题:hdu3037 Saving Beans #define LL long long LL PowMod(LL a,LL b,LL MOD){ LL ret=1; while(b){ if(b&1) ret=(ret*a)%MOD; a=(a*a)%MOD; b>>=1; } return ret; } LL fac[100005]; LL Get_Fact(LL p){ fac[0]=1; for(int i=1;i<=p;i++) fac[i]=(fac[i-1]*i)%p; } LL Lucas(LL n,LL m,LL p){ LL ret=1; while(n&&m){ LL a=n%p,b=m%p; if(a
LL F[100010]; void Get_F(LL p) { F[0] = 1; for(int i = 1;i <= p;i++) F[i] = F[i-1]*i%p; } //LL inv(LL a,LL m) //{ // if(a == 1)return 1; // return inv(m%a,m)*(m-m/a)%m; //} LL inv(LL x, LL M) { LL r, y; for (r = 1, y = M - 2; y; x = x * x % M, y >>= 1) (y & 1) && (r = r * x % M); return r; } LL Lucas(LL n,LL m,LL p) { LL ans = 1; while(n&&m) { LL a = n%p; LL b = m%p; if(a < b)return 0; ans = ans*F[a]%p*inv(F[b]*F[a-b]%p,p)%p; n /= p; m /= p; } return ans; }