紫书学习 10.数学概念与方法--计数问题基础
作者:互联网
基本计数原理
加法原理:做一件事情有n种办法,每种办法有pi种方案。
乘法原理:做一件事有n个步骤,每个步骤有pi种方案。
容斥原理:要计算一些互不独立的集合的并集,需要用到容斥原理。
比如求三个集合并的元素个数:
\[|A\cup B \cup C|=|A|+|B|+|C|-|A\cap B|-|A\cap C|-|B\cap C|+|A\cap B \cap C| \]左边是并,右边是交。右边,奇数时项为加号,偶数时的项为减号。
排列组合
有重复元素的全排列
假设有n种元素,每种元素可以选择\(p_i\)个,求全排列数。
可以采用消序法。假设\(\sum p_i=s\)
\[ans=A_s^s/(\prod A_{p_i}^{p_i}) \]可以重复选择的组合
假设有n种不同的元素,每种元素可以多次选择,最后选择k个元素,问有多少种方案。
假设每种元素选择\(p_i\)个,则根据问题列出表达式:
\[\sum p_i=k \]设表达式的一个解为\((p_1,p_2,...p_n)\),原问题即转化为求其非负整数解的个数。
等式两边同时+n,令\(p_i+1=y_i\),则原式转化为:
\[\sum y_i=n+k \]求该表达式的正整数解的个数。
这是经典的插板法的应用,相当于有\(n-k\)个1
,要在\(n+k-1\)个空隙中选n-1
个位置插板:\(ans=C_{n+k-1}^{n-1}\)
二项式系数的横向递推
根据二项式系数的表达式,容易得出:
\[C_n^i=C_n^{i-1}*(n-i+1)/i \]注意这种写法容易爆,而且不能把除法写到前面,因为不一定除得尽。
但是可以用这种方法递推出每个系数的唯一分解式,这是不会爆的。
约数个数
根据唯一分解表达式:
\[n=\prod p_i^{a_i} \]在根据乘法原理可得:
\[num=\prod(a_i+1) \]因此只需要对一个数做唯一分解,就可以求出它的约数个数。
欧拉函数
欧拉函数phi[i]
表示1~i中与i互素的数的个数。
容斥原理与欧拉函数
应用容斥原理。
1~n中总数为n。
首先从n中减去质因子\(p_i\)倍数的个数,即\(-\sum n/p_i\)
然后再加上同时是两个质因子倍数的个数,即\(+\sum n/(p_ip_j)\)
再减去是三个质因子倍数的个数
再加.......
这样计算的时间代价很高,有时甚至不如暴力枚举。
更简洁的等价表达式
\[\phi(i)=n*\prod(1- \frac{1}{p_i}) \]因此只需要一次质因数分解,就可以算出一个数的欧拉函数。
埃筛求1~n的欧拉函数
紫书上说,时间复杂度是\(O(nloglogn)\),比暴力快一些。
void cal_phi(int k){
phi[1]=1;
for(int i=2;i<=k;i++){
if(!phi[i]){
for(int j=i;j<=k;j+=i){
if(!phi[j])phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
埃筛求法比较直观,看上去,素数的相邻倍数之间的数应该是和素数倍数互素的。
欧拉筛求1~n的欧拉函数
用空间换时间,时间复杂度是线性的。
欧拉筛求欧拉函数的原理和表达式关系非常接近。
可以通过phi[i]
推出phi[primes[j]*i]
的值:
刚好欧拉筛就是用最小质因子来筛素数的,可以顺便求欧拉函数。
void cal_phi(int k){
phi[1]=1;
for(int i=2;i<=k;i++){
if(!st[i]){
phi[i]=i-1;//如果是素数,答案就是i-1
primes[++cnt]=i;
}
for(int j=1;primes[j]<=k/i;j++){
st[primes[j]*i]=1;
if(i%primes[j]){//pj不是最小质因子
phi[primes[j]*i]=phi[i]*(primes[j]-1)
}
else{//pj是i的最小质因子
phi[primes[j]*i]=phi[i]*primes[j];
break;
}
}
}
}
标签:10,phi,紫书,--,sum,cap,个数,表达式,欧拉 来源: https://www.cnblogs.com/tshaaa/p/16499912.html