容斥原理:
原理1:有I,j,p三个条件,假设满足条件i成立的事件数量为Si,满足条件I,j同时成立的事件数量为Si*Sj,满足事件I,j,p同时成立的事件数量为Si*Sj*Sp。则至少满足I,j,p其中一个条件的事件个数为Si+Sj+Sp-SiSj-SjSp-SiSp+SiSjSp。
原理2:有A,B,C三个事件,其中i事件成立的概率为Pi,则A,B,C中至少一个事件成立的概率为PA+PB+PC-PAPB-PAPC-PBPC+PAPBPC。
特别说明:以上原理可以推广至多个事件的情况,那么,最终的结果函数为
引例1:三个矩形在同一个平面存在,且三个矩形形可以进行重叠,求三个正方形所围成的几合图形的面积。
这样,由容斥性原理,S=S1+S2+S3-S12(12重叠的面积)-S13(13重叠的面积)-S23(23重叠的面积)+S123(123都重叠的面积)。
引例2:给出n的唯一分解式,
n=p1a1 p2a2·……·pnan,(pi为素因子)
求不大于n的所有正整数中,与n互素的数的个数。
n与p互素:当gcd(n,p)=1时,n与p互素。
定理:对于素数p,n与p互素,当且仅当n不是p的倍数。(证明很显然,略)
特别说明:n=Pa,那么不大于n的p的倍数的个数为Pa-1个。
证明:P*k= Pa ,解得:k=Pa-1。
所以,由容斥性原理,欧拉函数可以写成:
公式的数学意义:满足k<=n且k与n互素的k的个数。
基本总数为n,首先减去是p1,p2,…,pk倍数的个数(由互素定理),然后加上同时是两个素因子的倍数的个数,再减去同时是三个素因子的倍数的个数……扩展至n。
但是这样做在编程实现上并不占优势,时间复杂度甚至不如暴力解决。所以我们需要寻找更好的解决方式,但是对欧拉公式的理解至关重要。
由于数学家的贡献,可以知道欧拉公式等价于下面的形式。
该公式可以利用数学归纳法进行证明,但是我们可以对该公式进行理解性记忆,对照在概率论中学过的两个公式:
(1)( 1 – p1 ) ( 1 - p2 ) = 1 – p1 – p2 + p1p2
(2)( 1 - p1 ) ( 1 - p2 ) ( 1 – p3 ) = 1 – p1 – p2 - p3 + p1p2 + p2p3 + p1p3– p1p2p3
这样,对该公式的记忆变得不那么突兀。
这样,该问题就变的很好解决了。
值得一提的是,该问题如果需要求k<=n的欧拉函数表,下面的代码可以在O(nloglogn)的时间复杂度内完成全部欧拉函数值的计算。
intans[n+1];
voidphi_table(int n)
{
int i.j;
for(i=0;i<=n;i++) ans[i]=0;
ans[1]=1;
for(i=0;i<=n;i++) if(!ans[i])
for(j=I;j<=n;j+=i)
{
if(!ans[j]) ans[j]=j;
ans[j]=ans[j]/i*(i-1);
}
}
对该代码的理解:实际上是正面枚举任何一个比n小的数j,有多少个比j小的数是i 的倍数。与n有关的任意数i可以写成下面的形式:
j=a*i+b
这样,易知,当且仅当b=0时,j为i的倍数。
而b的取值范围是0 ~ i-1共i个数,而这i个数中只有1个是i的倍数。
由于a的可循环性,比j小的所有j个数中,每i个就有一个是i的倍数,其余均不是i的倍数,换句话说,其余i-1个数均与j互素。
这样的互素的数共有a = j / i 组,每组数中共有i-1个,所以满足条件的数共有j/i*(i-1)个。
这个理解是理解上述代码的基础。