组合数学
组合数取模
为方便, 记为 。
struct Combination//底数为0~n都求出来,对p取模
{
vector<vector<ll> > c;
Combination(int n,ll p):c(n+1,vector<ll>(1,1))//答案在c[n][m]中,时间复杂度O(N*N)
{
for(int i=1; i<=n; c[i++].push_back(1))
for(int j=1; j<i; ++j)
c[i].push_back((c[i-1][j-1]+c[i-1][j])%p);
}
};
struct CombinatorialNumber//节省空间,只保存以n为底对p取模的结果,时间复杂度O(NlogN),其中log来自于乘法逆元
{
vector<ll> c;
CombinatorialNumber(int n,ll p):c(n+1,1)
{
for(int i=1; i<=n; ++i)
c[i]=c[i-1]*(n-i+1)%p*inv(i,p)%p;
}
};
ll lucas(ll n,ll m,ll p)//卢卡斯定理求C(n,m)%p,时间复杂度O(min(n,p))
{
if(!m)return 1;
if(n<m||n%p<m%p)return 0;
if(n>=p||m>=p)return lucas(n/p,m/p,p)*lucas(n%p,m%p,p)%p;
ll a=1,b=1;//此时有0<m<n<p,可考虑优化用上面的结果来求
for(m=min(m,n-m); m;)//暴力求
a=a*n--%p,b=b*m--%p;
return a*inv(b,p)%p;
}
Stirling数
第一类斯特林数
第一类斯特林数
的一个的组合学解释是:将p个物体排成k个非空循环排列的方法数。
递推公式:
第二类斯特林数
第二类斯特林数
的一个的组合学解释是:将p个物体划分成k个非空不可辨别的(可以理解为盒子没有编号)集合的方法数。
递推公式:
卷积形式:
同时有转化:
斯特林近似公式
小球入盒问题
k 个球 | m个盒子 | 空盒子 | 方案数 |
---|---|---|---|
各不相同 | 各不相同 | 允许 | |
各不相同 | 各不相同 | 无 | |
各不相同 | 完全相同 | 允许 | |
各不相同 | 完全相同 | 无 | |
完全相同 | 各不相同 | 允许 | |
完全相同 | 各不相同 | 无 | |
完全相同 | 完全相同 | 允许 | |
完全相同 | 完全相同 | 无 |
Catalan数
。
在一个格点阵列中,从(0,0)点走到(n,m)点且不经过对角线x=y的方法数:
。
Bell数
把n个带标号的物品划分为若干不相交集合的方案数称为贝尔数,其递推公式:
下为
求
对P取模。
struct Bell {
static const int P=999999598,N=7284;
int a[4],f[N],s[2][N],i,j,x;
Bell() {
a[0]=2,a[1]=13,a[2]=5281,a[3]=7283;//P的质因数分解
f[0]=f[1]=s[0][0]=1,s[0][1]=2;
for(i=2,x=1; i<N; i++,x^=1)
for(f[i]=s[x][0]=s[x^1][i-1],j=1; j<=i; ++j)
s[x][j]=(s[x^1][j-1]+s[x][j-1])%P;
}
int cal(int x,ll n) {
int i,j,k,m=0,b[N],c[N],d[70];
for(i=0; i<=x; i++)b[i]=f[i]%x;
while(n)d[m++]=n%x,n/=x;
for(i=1; i<m; i++)for(j=1; j<=d[i]; j++) {
for(k=0; k<x; k++)c[k]=(b[k]*i+b[k+1])%x;
c[x]=(c[0]+c[1])%x;
for(k=0; k<=x; k++)b[k]=c[k];
}
return c[d[0]];
}
ll ask(ll n) {
if(n<N)return f[n];
ll t=0;
for(int i=0; i<4; ++i)t=(t+(P/a[i])*pow(P/a[i],a[i]-2,a[i])%P*cal(a[i],n)%P)%P;
return t;
}
};
等价类容斥
考虑容斥,Bell(p)枚举所有等价情况。对于一种情况,强制了一个等价类里面的数都要相同,其它的可以相同也可以不同。
容斥系数为:
。
贝尔数前若干项的表:
扩展Cayley公式
对于n个点,m个连通块的图,假设每个连通块有a[i]个点,那么用s−1条边把它连通的方案数为 。
超立方体
n维超立方体有 个i维元素。
固定 k 个点为根的带标号有根树森林计数
固定k个点作为根的n个点的带标号有根树森林的方案数是 。