《Introductory Combinatorics Fifth Edition》学习笔记:
四个基本计数原理:
@加法原理:设集合s划分为两两互不相交的各个部分s1,s2,s3……sn,那么s的元素总个数等于各个部分的总个数之和。即|s|=|s1|+|s2|+……+|sn|.(如果允许子部分相交,则需要用容斥原理来解决)使用加法原理的技巧是:把原集合分割成容易处理的少量子集。分析:一个正整数可以进行唯一的素因子分解,比如12=2^2*3,那么12的正因子为2的指数总个数和3的指数总个数之积;3*2=6.
#include <iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; const int maxn=1e8+1,maxn2=1e7; int pri[maxn2],top=0,pow[maxn2]; bool notpri[maxn]; void getpri(){ for(int i=2;i<maxn;i++){ if(!notpri[i])pri[top++]=i; for(int j=0;j<top&&pri[j]*i<maxn;j++){ notpri[pri[j]*i]=1; if(i%pri[j]==0)break; } } } int main() { //freopen("cin.txt","r",stdin); LL n,top2=0,i; getpri(); while(cin>>n){ top2=0; memset(pow,0,sizeof(pow)); for(i=0;i<top;i++){ if(n==1)break; if(n%pri[i]==0){ top2++; while(n%pri[i]==0){ n/=pri[i]; pow[top2]++; } } } int sum=1; for(i=1;i<=top2;i++){ sum*=(pow[i]+1); } printf("%d\n",sum); } return 0; }巧用乘法原理:
@减法原理:令U是一个包含A的集合,设A'=U/A={x属于U但是不属于A},称A'是A在U中的补集。|A|=|U|-|A'|.
例子:有多少个各位数字互不相同且不为0的两位数?
用乘法原理做:9*8=72.
减法原理做:两位数字一共有90个(99-9=90),存在位数有0的有(10,20……90)9个,位数相同的两位数有(11,22,33……99)9个,所以满足条件的一共有90-9-9=72个。
@除法原理:如果知道了s中的对象数目以及各部分所含对象数目的共同值,就可以确定部分的数目。k=|s|/|s(k)|.
例子(严格的说是排列的例子): 数字1,1,1,3,8能够构造多少个不同的5位数?
s=A(5,5)/A(3,3)=5*4=20.(用乘法原理同样能分析出来)