zoukankan      html  css  js  c++  java
  • 总结组合数的几种求法(模板)


    way1.打表C(n,m)

    原理:

    • 杨辉三角
    • (sum_{i=m}^{n}C_{i}^{m}=C_{n+1}^{m+1})
    • 即下图中绿色方框的数等于红色方框内数的总和:

    空间:

    • O(nm)

    时间:

    • 预处理O(nm)
    • 查询O(1)
    for(int i=0;i<=n;i++){
    	c[i][0]=c[i][i]=1;
    	for(int j=1;j<i;j++)
    		c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    

    way2. 阶乘无模

    原理:

    • 组合数基本公式
    • (C_n^m=frac{n!}{m!(n-m)!})

    空间:

    • O(n)

    时间:

    • 预处理O(1)
    • 查询O(n)

    但这有个缺点就是涉及除法,无法直接取模

    所以我们就要引入乘法逆元:


    way3.乘法逆元+快速幂+阶乘

    原理:

    • 费马小定理:
    • (a^{p-1} equiv 1 (mod\, p)) (p是素数)
    • 两边同除a得:
    • (a^{p-2} equiv frac{1}{a} (mod\, p))
    • 我们知道mod p意义下(frac{1}{a})就是a的逆元
    • 因此可得mod p意义下a的逆元(inv(a)=a^{p-2})
    • 而这个(a^{p-2})又可以用快速幂一只log求得

    空间:

    • O(n)

    时间:

    • 预处理O(n)
    • 查询O(log p)
    int pow(int x,int y){ //快速幂
    	int res=1;
    	x%=p;
    	for(;b;b>>=1,a=a*a%p) if(b&1) res=res*a%p;
        return res;
    }
    int inv(int x,int p){ //求逆元
    	return pow(x,p-2);
    }
    fac[0]=1;
    for(int i=1;i<=n;i++)
    	fac[i]=fac[i-1]*i; //预处理出阶乘
    return ((fac[n]*inv(fac[m],p))%p*inv(fac[n-m],p))%p;
    

    way4.Lucas定理

    Lucas定理是用于处理组合数取模的定理

    通常用于解决阶乘无法解决的问题。

    原理:

    • (Lucas(n,m,p): mod: p=Lucas(frac{n}{p},frac{m}{p},p)*C_{n: mod: p}^{m: mod: p}: mod: p)
    • (Lucas(n,m,p): mod: p=C_n^m: mod : p)

    洛谷P3807为例

    #define int long long
    int t,n,m,p,f[100005];
    int pow(int x,int y,int p){ //快速幂
    	x%=p;
    	int ans=1;
    	for(int i=y;i;i>>=1,x=x*x%p) if(i&1) ans=ans*x%p;
    	return ans;
    }
    int C(int n,int m,int p){ //求组合数
    	if(m>n) return 0;
    	return ((f[n]*pow(f[m],p-2,p))%p*pow(f[n-m],p-2,p)%p);
    }
    int lucas(int n,int m,int p){ //Lucas定理
    	if(!m) return 1;
    	return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
    }
    signed main(){
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d%d",&n,&m,&p);
    		f[0]=1;
    		for(int i=1;i<=p;i++)
    			f[i]=(f[i-1]*i)%p;
    		printf("%lld
    ",lucas(n+m,m,p));
    	}
    }
    
  • 相关阅读:
    ie6 ie7 ie8 ie9 firefox css hack
    小型数据分页
    AsyncTask 使用须知
    调用startActivityForResult,onActivityResult无响应的问题
    Android之背景图片设置为重复而不是默认的拉伸
    Android Service之Messenger实现通信
    android之.9.png图片应用
    小米2及其他Android手机无法连接mac解决方案
    纯CSS3打造滑动下拉导航菜单
    DIV制作气泡对话框 兼容IE6
  • 原文地址:https://www.cnblogs.com/think-twice/p/11205353.html
Copyright © 2011-2022 走看看