简单组合计数
组合计数基础
几个原理:
1.加法原理:若完成一件事有\(n\)类不同的方法,第\(i\)类方法有\(a_i\)种方法,且这些方法互不重合则完成这件事共有\(\sum_{i=1}^na_i\)种方法
2.乘法原理:若完成一件事有\(n\)个不同的步骤,每个步骤有\(a_i\)种完成方法,且互不干扰,则完成该件事共有\(\prod_{i=1}^na_i\)种方法
几个定义:
1.排列数:从\(n\)个不同的数里依次 取出\(m\)个,产生的不同排列数量为:
\[A_n^m(\text{或}P_n^m)=\prod_{i=n-m+1}^n i=\frac{n!}{(n-m)!} \]注意是\(m\)在上
2.组合数:从\(n\)个不同的数里取出\(m\)个组成一个集合(不考虑顺序,只要元素到位),产生的不同集合数量为:
\[C_n^m=\frac{A_n^m}{m!}=\frac{n!}{m!(n-m)!} \]性质:
1.\(C_n^m=C_n^{n-m}\)
2.\(C_n^m=C_{n-1}^m+C_{n-1}^{m-1}\) 重要
3.\(\sum_{i=0}^nC_n^i=2^n\)
4.\(\sum_{k=0}^n(-1)^kC_n^k=0\)
5.\(C_{m+n}^k=\sum_{j=0}^k(C_m^{k-j}\times C_n^j)\)
6.\(C^{k+1}_ {n+1} =\sum_{i=k}^nC_i^k\)
7.Lucas定理:若\(p\)是质数,则对于任意整数\(1\le m\le n\)有
\[C_n^m\equiv C^{m \bmod p}_ {n\bmod p}\times C^{\lfloor \frac{m}{p} \rfloor}_ {\lfloor \frac{n}{p} \rfloor} (\bmod p) \]这个注意代码实现的时候得递归实现
二项式定理
\[(a+b)^n=\sum_{k=0}^nC_n^ka^kb^{n-k} \]多项式定理
设\(n\)是正整数,则对于所有的\(x_i\) \((i\in [1,t])\)有
\[(\sum_{i=1}^tx_i)^n=\sum_{\left(\sum_{p=1}^tn_p\right)=n}\left(\frac{n!}{\prod_{k=1}^t(n_k!)}\right)\prod_{j=1}^tx_j^{n_j} \]这里把\(n_i\)的所有组合枚举出来即可
多重集的排列数
多重集是允许包含重复元素的集合,设集合\(\mathbb{S}={\lbrace n_1·a_1,n_2·a_2,n_3·a_3…n_k·a_k\rbrace}\)是由\(n_1\)个\(a_1\)……组成的多重集,\(n=\sum_{i=1}^kn_i\)则它的全排列个数为:
\[\frac{n!}{\prod_{k=1}^m(n_k!)} \]多重集的组合数
设集合\(\mathbb{S}={\lbrace n_1·a_1,n_2·a_2,n_3·a_3…n_k·a_k\rbrace}\)是由\(n_1\)个\(a_1\)……组成的多重集,\(n=\sum_{i=1}^kn_i\)
则从该集合中选出\(r(r\le n)\)个数组成的不同的多重集数量为:
Catlan数
定义
\[Cat_n=C_{2n}^n-C_{2n}^{n-1}=\frac{C_{2n}^n}{n+1} \]与其有关的问题:
1.给定n个左括号和n个右括号组成合法的括号序列的个数为\(Cat_n\)
2.\(1\sim n\)依次进栈,合法的出栈序列个数为\(Cat_n\)
3.n个节点组成的不同二叉树的数量是\(Cat_n\)
4.在平面直角坐标系中每一步只能向上或者向右走,从点\((0,0)\)到点\((n,n)\)并且除了两个端点之外路线上没有一个点经过直线y=x,这样的路径条数一共有\(2Cat_{n-1}\)
几个结论:
1.将一个长度为n的环变作n个自环至少要将节点交换n-1次
2.设\(F_n\)表示用最少步骤将一个长度为n的环变作n个自环的操作方案数,有:\(F_n=n^{n-2}\)
3.遇到序列上的错位,需要交换位置还原的问题可以往图论方向想
exlucas
用途:快速求出以下式子的值(p不一定是质数)
\[C_n^m \bmod p \]遇到这种情况,我们可以将p进行算术基本定理的质因数分解。设\(p=\prod_{i=1}^kp_i^{c_i}\),我们设\(a_i=C_n^m \bmod p_i^{c_i}\)
这样我们就把问题简化成了:
\[\left\{ \begin{aligned} x \bmod& p_1^{c_1}=a_1 \\ x \bmod& p_2^{c_2}=a_2 \\ x \bmod& p_3^{c_3}=a_3 \\ &\vdots \\ x \bmod& p_k^{c_k}=a_k \\ \end{aligned} \right. \]这个一次同余式组直接用中国剩余定理\(CRT\)求即可
问题在于如何求出\(C_n^m \bmod p_i^{c_i}\)
先来看简化版扩展卢卡斯:
题意:给定整数\(n,q(n,q\le 10^9)\)计算
\[q^{\sum_{d|n}C_n^d } \bmod 999911659 \]因为999911659是一个质数,由扩欧得:
原式等价于
\[q^{\sum_{d|n}C_n^d \bmod 999911658} \bmod 999911659 \]所以本题关键在于计算\(\sum_{d|n}C_n^d \bmod 999911658\)
按照扩展卢卡斯的思路,我们将999911658分解质因数发现:\(999911658=2\times 3\times 4679 \times 35617\)
我们枚举n的约数d,分成四个,运用Lucas定理分别计算组合数\(C_n^d\)对这四个质因数的模,求出\(\sum_{d|n}C_n^d\)模这四个质数的值,记作\(a_1,a_2,a_3,a_4\)
当然对于质数的逆元啥的自己预处理一下就可以
现在我们的问题就是求解同余方程组
\[\left\{ \begin{aligned} x \bmod& 2&=&a_1 \\ x \bmod& 3&=&a_2 \\ x \bmod& 4679&=&a_3 \\ x \bmod& 35617&=&a_4 \\ \end{aligned} \right. \]然后用快速幂进行计算即可
#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;
}
这也就是所有的\(c_i=1\)时的简化情况
标签:frac,组合,int,bmod,多重集,计数,简单,prod,sum From: https://www.cnblogs.com/oierpyt/p/16939975.html