简单组合计数

简单组合计数

组合计数基础

几个原理:

1.加法原理:若完成一件事有n类不同的方法,第i类方法有ai种方法,且这些方法互不重合则完成这件事共有i=1nai种方法

2.乘法原理:若完成一件事有n个不同的步骤,每个步骤有ai种完成方法,且互不干扰,则完成该件事共有i=1nai种方法

几个定义:

1.排列数:从n个不同的数里依次 取出m个,产生的不同排列数量为:

Anm(Pnm)=i=nm+1ni=n!(nm)!

注意是m在上

2.组合数:从n个不同的数里取出m个组成一个集合(不考虑顺序,只要元素到位),产生的不同集合数量为:

Cnm=Anmm!=n!m!(nm)!

性质:

1.Cnm=Cnnm

2.Cnm=Cn1m+Cn1m1      重要

3.i=0nCni=2n

4.k=0n(1)kCnk=0

5.Cm+nk=j=0k(Cmkj×Cnj)

6.Cn+1k+1=i=knCik

7.Lucas定理:若p是质数,则对于任意整数1mn

CnmCnmodpmmodp×Cnpmp(modp)

这个注意代码实现的时候得递归实现

二项式定理

(a+b)n=k=0nCnkakbnk

多项式定理

n是正整数,则对于所有的xi (i[1,t])

(i=1txi)n=(p=1tnp)=n(n!k=1t(nk!))j=1txjnj

这里把ni的所有组合枚举出来即可

多重集的排列数

多重集是允许包含重复元素的集合,设集合S={n1·a1,n2·a2,n3·a3nk·ak}是由n1a1……组成的多重集,n=i=1kni则它的全排列个数为:

n!k=1m(nk!)

多重集的组合数

设集合S={n1·a1,n2·a2,n3·a3nk·ak}是由n1a1……组成的多重集,n=i=1kni
则从该集合中选出r(rn)个数组成的不同的多重集数量为:

Ck+r1k1i=1kCk+rni2k1+1i<jnCk+rninj2k1+(1)kCk+rnk1k1

Catlan数

定义

Catn=C2nnC2nn1=C2nnn+1

与其有关的问题:

1.给定n个左括号和n个右括号组成合法的括号序列的个数为Catn

2.1n依次进栈,合法的出栈序列个数为Catn

3.n个节点组成的不同二叉树的数量是Catn

4.在平面直角坐标系中每一步只能向上或者向右走,从点(0,0)到点(n,n)并且除了两个端点之外路线上没有一个点经过直线y=x,这样的路径条数一共有2Catn1

几个结论:

1.将一个长度为n的环变作n个自环至少要将节点交换n-1次

2.设Fn表示用最少步骤将一个长度为n的环变作n个自环的操作方案数,有:Fn=nn2

3.遇到序列上的错位,需要交换位置还原的问题可以往图论方向想

exlucas

用途:快速求出以下式子的值(p不一定是质数)

Cnmmodp

遇到这种情况,我们可以将p进行算术基本定理的质因数分解。设p=i=1kpici,我们设ai=Cnmmodpici

这样我们就把问题简化成了:

{xmodp1c1=a1xmodp2c2=a2xmodp3c3=a3xmodpkck=ak

这个一次同余式组直接用中国剩余定理CRT求即可

问题在于如何求出Cnmmodpici

先来看简化版扩展卢卡斯:

古代猪文

题意:给定整数n,q(n,q109)计算

qd|nCndmod999911659

因为999911659是一个质数,由扩欧得:

原式等价于

qd|nCndmod999911658mod999911659

所以本题关键在于计算d|nCndmod999911658

按照扩展卢卡斯的思路,我们将999911658分解质因数发现:999911658=2×3×4679×35617

我们枚举n的约数d,分成四个,运用Lucas定理分别计算组合数Cnd对这四个质因数的模,求出d|nCnd模这四个质数的值,记作a1,a2,a3,a4

当然对于质数的逆元啥的自己预处理一下就可以

现在我们的问题就是求解同余方程组

{xmod2=a1xmod3=a2xmod4679=a3xmod35617=a4

然后用快速幂进行计算即可

#define int long long 
int mod=999911659,p[4]={2,3,4679,35617},n,m,cnt,ans,q;
int ys[40000],jc[40000],a[4],x,y,t;
int power(int a,int b,int p){
    int ans=1;
    while(b){
    	if(b&1)ans=ans*a%p;
    	a=a*a%p;
    	b>>=1;
	}
    return ans;
}
int C(int n,int m,int p){
    return n<m?0:jc[n]*power(jc[m]*jc[n-m],p-2,p)%p;
}
int lucas(int n,int m,int p){
    return m?C(n%p,m%p,p)*lucas(n/p,m/p,p)%p:1;
}
int exgcd(int a,int b,int &x,int &y){
    if(!b){
    	x=1,y=0;
    	return a;
	}
	int d=exgcd(b,a%b,x,y);
	int t=x;
	x=y,y=t-(a/b)*y;
	return d;
}
signed main(){
    scanf("%lld%lld",&n,&q);
    if(q%mod==0){
        puts("0");
        return 0;
    }
    jc[0]=1;
    m=sqrt(n);
    for(int i=1;i<=m;i++){
        if(n%i==0){
			ys[++cnt]=i,ys[++cnt]=n/i;
		}
	}
    cnt-=ys[cnt-1]==ys[cnt];
    for(int i=0;i<4;i++){
        for(int j=1;j<p[i];j++){
			jc[j]=jc[j-1]*j%p[i];
		}
        for(int j=1;j<=cnt;j++){
			a[i]=(a[i]+lucas(n,ys[j],p[i]))%p[i];
		}
        exgcd((mod-1)/p[i],p[i],x,y);
        ans=(ans+a[i]*(x%p[i]+p[i])*(mod-1)/p[i])%(mod-1);
    }
    printf("%lld\n",power(q,ans,mod));
    return 0;
}
 

这也就是所有的ci=1时的简化情况

posted @   spdarkle  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示