求排列组合的几种方法

求组合数

递推法:

C a b = C a − 1 b + C a − 1 b − 1 C_a^b=C_{a-1}^b+C_{a-1}^{b-1} Cab=Ca1b+Ca1b1
一般 a , b ≤ 2000 a,b\le2000 a,b2000 ,预处理时间复杂度: O ( n 2 ) O(n^2) O(n2)

代码:

#define NUMBER1 1919
const int mod=1801;
typedef long long LL;
LL c[114][514];
inline void inint(){
    for(register int i(0);i<NUMBER1;i=-~i)
       for(register int j(0);j<=i;j=-~j)
           if(!j)c[i][j]=1;
           else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
逆元法(取模数为质数):

预处理时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
代码:

#define NUMBER1 100000
typedef long long LL;
const int mod=1e9+7;
int fact[NUMBER1+5],infact[NUMBER1+5]
inline LL quick_mod(LL a,LL b){
    LL ans(1);
    while(b){
        if(b&1)ans=a*ans%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
inline void inint(){
    fact[0]=infact[0]=1;
    for(register int i(1);i<NUMNER1;i=-~i){
        fact[i]=1LL*fact[i-1]*i%mod;
        infact[i]=1LL*infact[i-1]*quick_mod(i,mod-2)%mod;
    }
}
signed main(){
    LL ans=1LL*fact[a]*infact[b]%mod*infact[a-b]%mod;
    return 0;
}
卢卡斯定理法(Lucas):

数据范围: ( a , b ∈ [ 1 , 1 0 18 ] , p ∈ [ 1 , 1 0 15 ] ) (a,b\in[1,10^{18}],p\in[1,10^{15}]) (a,b[1,1018],p[1,1015])
原理:
C a b ≡ C a   m o d   p b   m o d   p ∗ C a / p b / p ( m o d p ) C_a^b \equiv C_{a \bmod p}^{b\bmod p}* C_{a/p}^{b/p} \pmod p CabCamodpbmodpCa/pb/p(modp)
查询时间复杂度: O ( log ⁡ p N + p log ⁡ p ) O(\log_pN+ p\log p) O(logpN+plogp) ,约为 4 ∗ 1 0 7 4* 10^7 4107

代码:

LL p;
inline LL quick_mod(LL a,LL b){
	LL ans(1);
	while(b){
		if(b&1)ans=ans*a%p;
		b>>=1,a=a*a%p;
	}
	return ans;
}
inline LL C(LL a,LL b){
	LL ans(1);
	for(register int i(1),j=a;i<=b;i=-~i,--j)
		ans=ans*j%p*quick_mod(i,p-2)%p;
	return ans;
}
inline LL Lucas(LL a,LL b){
	if(a<p||b<p)return C(a,b);
	return C(a%p,b%p)*Lucas(a/p,b/p)%p;
}
signed main(){
    ans=Lucas(a,b);
    return 0;
}
高精度(没有取模)

数据范围: ( a , b ∈ [ 1 , 5000 ] ) (a,b\in[1,5000]) (a,b[1,5000])
思路:分解质因数,最后再乘。
时间复杂度: b 2 b^2 b2

代码:

#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cctype>
#define P(A) A=-~A
#define fione_i(a,b) for(register int i=a;i<=b;P(i))
#define fione_j(a,b) for(register int j=a;j<=b;P(j))
typedef long long LL;
namespace FastIo{
    static char buf[100000],*p1=buf,*p2=buf,fw[100000],*pw=fw;
    #define gc p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++
    inline void pc(const char &ch){
    	if(pw-fw==100000)fwrite(fw,1,100000,stdout),pw=fw;
    	*pw++=ch;
	}
    #define fsh fwrite(fw,1,pw-fw,stdout),pw=fw
	struct ubint{
		int len,num[100005];
		ubint(){len=0;memset(num,0,sizeof(num));}
		void operator=(int a){
			memset(num,0,sizeof(num));
			len=0; 
			do{
				num[++len]=a%10;
				a/=10;
			}while(a);
		}
		ubint operator*(int a)const{
			ubint res;
			res.len=len;
			fione_i(1,res.len){
				res.num[i]+=a*num[i];
				res.num[i+1]=res.num[i]/10;
				res.num[i]%=10;
			}
			while(res.num[res.len+1]){
				P(res.len);
				res.num[res.len+1]+=res.num[res.len]/10;
				res.num[res.len]%=10;
			}
			return res;
		}
	};
    struct QIO{
    	char ch;
    	inline void read(int &x){
    		x=0,ch=gc;
    		while(!isdigit(ch))ch=gc;
    		while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
		}
		inline void write(ubint a){while(a.len)pc(a.num[a.len--]^48);}
	}qrw;
}
using namespace FastIo;
#define NUMBER1 5000
int prime[NUMBER1+5],cnt(0),sum[NUMBER1+5];
bool st[NUMBER1+5];
inline int get(int n,int p){
	int ans(0);
	while(n){
		ans+=n/p;
		n/=p;
	}
	return ans;
}
inline void PRIME(){
	fione_i(2,NUMBER1){
		if(!st[i])prime[++cnt]=i;
		for(register int j(1);prime[j]*i<=NUMBER1;P(j)){
			st[prime[j]*i]=true;
			if(!(i%prime[j]))break;
		}
	}
}
ubint ans;
signed main(){
	PRIME();
	int a,b;
	ans=1;
	qrw.read(a);
	qrw.read(b);
	fione_i(1,cnt)sum[i]=get(a,prime[i])-get(a-b,prime[i])-get(b,prime[i]);
	fione_i(1,cnt)
		while(sum[i]--)ans=ans*prime[i];
	qrw.write(ans);
	fsh;
    exit(0);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值