/**
* 快速幂取模算法
* 分析:a^b mod c = (a mod c)^b mod c
* a^b mod c = (a^2)^b/2 mod c , b为偶数
* a^b mod c = ((a^2)^b/2·a) mod c , b为奇数
* 每次让指数折半
*/
private static final long mod = 1000000007;
public long pow_mod(long a,long b){
long res = 1;
a %= mod;
for (;b > 0;b/=2){
if ((b&1)==0?false:true) //如果指数是奇数,(Java不会自动int转boolean)
res = (res * a) % mod;//先把所以奇数次幂时剩下的a先乘起来,最后当b=1时,再全部乘起来。
a = (a * a) % mod;
}
return res;
}
@Test
public void test1(){
long res = pow_mod(2, 10);
System.out.println(res);
}
/**
* 乘积逆元取模
* 除法求模不能类似乘法,对于(A/B)mod C,直接(A mod C)/ (B mod C)是错误的;
* 找到B的逆元b(b=B^-1);求出(A*b)modC即可;
*
* a^-1=a^(p-2)
* //p为素数时,a的逆元就是a^(p-2),就直接用快速幂求出a^(p-2)即是a的逆元
*/
public long getinv(long a){
return pow_mod(a,mod-2);
}
/**
* 求排列组合
* A(n,m)= n!/(n-m)!
* C(n,m)= n!/(m!*(n-m)!)
*/
private final int G = 10000;
private long[] fac = new long[G];//存储阶乘 factorial
private long[] inv = new long[G];//储存阶乘逆元
public void getFactorial(){
fac[0] = 1;// 0! = 1
inv[0] = 1;
for (int i = 1;i < G;i++){
fac[i] = (fac[i-1] * i)% mod;
inv[i] = getinv(fac[i])%mod;
}
}
//求排列组合数
public long C(int n,int m){// C(n,m)= n!/(m!*(n-m)!)
return fac[n]*inv[m]%mod*inv[n-m]%mod;//千万注意,取两次mod 不然可能数会越界
}
@Test
public void test2(){
getFactorial();
System.out.println(Arrays.toString(fac));
System.out.println(Arrays.toString(inv));
System.out.println(C(8, 4));
}
求组合数(快速幂+逆元)
最新推荐文章于 2024-07-24 22:13:06 发布