typedef int arr[maxn][maxn];
从 n n n个不同的元素中,取 m m m个不重复的元素,按次序排列,称为从 n n n个中取 m m m个的排列。
A n m = n ! ( n − m ) ! A_n^m=\frac{n!}{(n-m)!} Anm=(n−m)!n!
从 n n n个不同的元素中,取 m m m个不重复的元素,不考虑次序,称为从 n n n个中取 m m m个的组合。
C n m = n ! ( n − m ) ! ( m ! ) C_n^m=\frac{n!}{(n-m)!(m!)} Cnm=(n−m)!(m!)n!
组合数的性质:
C n m = C n n − m ∑ i = 0 n C n i = 2 n C n m = C n − 1 m + C n − 1 m − 1 \begin{aligned} C_n^m&=C_n^{n-m}\\ \sum_{i=0}^nC_n^i&=2^n\\ C_n^m&=C_{n-1}^m+C_{n-1}^{m-1} \end{aligned} Cnmi=0∑nCniCnm=Cnn−m=2n=Cn−1m+Cn−1m−1
解读:
根据 C n m = C n − 1 m + C n − 1 m − 1 C_n^m=C_{n-1}^m+C_{n-1}^{m-1} Cnm=Cn−1m+Cn−1m−1递推求组合数:
void make_C(arr C,int n){
for(int i=0;i<=n;i++)C[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
根据定义式推出 C n i = C n i − 1 n − i + 1 i C_n^i=C_n^{i-1}\frac{n-i+1}i Cni=Cni−1in−i+1求出某一行组合数:
void make_Cn(int*C,int n){
C[0]=1;
for(int i=1;i<=n;i++)C[i]=C[i-1]*(n-i+1)/i;
}
( x + y ) n = ∑ k = 0 n C n k x n − k y k (x+y)^n=\sum_{k=0}^nC_n^kx^{n-k}y^k (x+y)n=k=0∑nCnkxn−kyk
求 C n m m o d p C_n^m\mod p Cnmmodp的值( p p p为质数)。
C n m ≡ C n m o d p m m o d p C ⌊ n p ⌋ ⌊ m p ⌋ ( m o d p ) C_n^m\equiv C_{n\mod p}^{m\mod p}C_{\lfloor\frac np\rfloor}^{\lfloor\frac mp\rfloor}\pmod p Cnm≡CnmodpmmodpC⌊pn⌋⌊pm⌋(modp)
不想证明。
时间复杂度: O ( p log p m ) O(p\log_pm) O(plogpm)
int C(int a,int b,int p){
if(a<b)return 0;
if(a==b)return 1;
if(b>a-b)b=a-b;
int A=1,B=1;
for(int i=0;i<b;i++)A=A*(a-i)%p,B=B*(b-i)%p;
return A*Pow(B,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;
}
求 C n m m o d p C_n^m\mod p Cnmmodp的值( p p p不一定为质数)。
首先将 p p p分解质因数: p = p 1 k 1 p 2 k 2 p 3 k 3 … p q k q p=p_1^{k_1}p_2^{k_2}p_3^{k_3}\dots p_q^{k_q} p=p1k1p2k2p3k3…pqkq
然后得出一个同余方程组,用中国剩余定理求解。
{ x ≡ C n m m o d p 1 k 1 ( m o d p 1 k 1 ) x ≡ C n m m o d p 2 k 2 ( m o d p 2 k 2 ) ⋮ x ≡ C n m m o d p q k q ( m o d p q k q ) \begin{cases} x&\equiv C_n^m\mod p_1^{k_1}\pmod{p_1^{k_1}}\\ x&\equiv C_n^m\mod p_2^{k_2}\pmod{p_2^{k_2}}\\ &\vdots\\ x&\equiv C_n^m\mod p_q^{k_q}\pmod{p_q^{k_q}} \end{cases} ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧xxx≡Cnmmodp1k1(modp1k1)≡Cnmmodp2k2(modp2k2)⋮≡Cnmmodpqkq(modpqkq)
k i > 1 k_i>1 ki>1时, C n m m o d p i k i C_n^m\mod p_i^{k_i} Cnmmodpiki怎么计算?待补充。
第二类Stirling数表示把 n n n个元素划分成 m m m个非空集合的方案数。
S n m = S n − 1 m − 1 + m S n − 1 m S_n^m=S_{n-1}^{m-1}+mS_{n-1}^m Snm=Sn−1m−1+mSn−1m
递推过程: 若前 n − 1 n-1 n−1个元素已经分成了 m − 1 m-1 m−1个集合,则第 n n n个元素自成一个集合,否则把第 n n n个元素放入 m m m个集合中的任意一个集合中。
void make_s2(arr s2,int n){
s2[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
s2[i][j]=s2[i-1][j-1]+j*s2[i-1][j];
}
第一类Stirling数表示把 n n n个元素划分成 m m m个非空循环排列集合的方案数。
s n m = s n − 1 m − 1 + ( n − 1 ) s n − 1 m s_n^m=s_{n-1}^{m-1}+(n-1)s_{n-1}^m snm=sn−1m−1+(n−1)sn−1m
递推过程: 若前 n − 1 n-1 n−1个元素已经分成了 m − 1 m-1 m−1个集合,则第 n n n个元素自成一个集合,否则把第 n n n个元素放入前 n − 1 n-1 n−1个元素中任意一个元素的左边。
void make_s1(arr s1,int n){
s1[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
s1[i][j]=s1[i-1][j-1]+(i-1)*s1[i-1][j];
}
Bell数表示把 n n n个元素划分成若干个非空集合的方案数。
B n = ∑ k = 1 n S n k B_n=\sum_{k=1}^nS_n^k Bn=k=1∑nSnk
C n = { 1 n = 1 4 n − 2 n + 1 C n − 1 otherwise C_n=\begin{cases} 1&n=1\\ \frac{4n-2}{n+1}C_{n-1}&\text{otherwise} \end{cases} Cn={1n+14n−2Cn−1n=1otherwise
C n = C 2 n n n + 1 = C 2 n n − C 2 n n − 1 C_n=\frac{C_{2n}^n}{n+1}=C_{2n}^n-C_{2n}^{n-1} Cn=n+1C2nn=C2nn−C2nn−1
问题描述:
这些问题的答案都是Catalan数或与Catalan有关。
答案是多少呢?我忘了。
...
void make_catalan(unsigned_Int*h,int n){
h[1]=1;
for(int i=2;i<=n;i++)h[i]=h[i-1]*(4*i-2)/(i+1);
}
其中unsigned_Int
为高精度非负整数类型。