唯一分解定理
- 算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。(这个定理真的是有趣)
约数的个数
描述:
给出正整数n的唯一分解式n=,求n的正整数的个数。
分析:
不难看出,n的任意正约数也只能包含p1,p2,p3等素因子,而不能有新的素因子出现。对于n的某个素因子,它在所求约数中的指数可以是0,1,2,···,共+1种情况,而且不同的素因子之间相互独立。根据乘法原理,n的正约数个数为:
小于n且与n互素的个数
描述:
给出正整数n的唯一分解式n=,求1,2,3,···,n中与n互素的数的个数。
分析:
用容斥原理。首先从总数n中分别减去p1,p2,···,·pk的倍数(对于素数p来说,“与p互素”和“不是p的倍数等价”),即,然后加上“同时是两个素因子的倍数”的个数,再减去“同时是3个素因子的倍数”——写成一个“学术味比较浓”的公式就是:
,
这里引入的新记号就是题目中所求的结果,称为欧拉函数。强烈建议初学者花一些时间理解这个公式(也是对自己说的)。对于{p1,p2,···,pk}的任意子集S,“不与其中任何一个互素”的元素个数是。不过这一项的前面是加号还是减号呢?这取决于S中的元素个数——奇数个就是“减号”,偶数个是“加号”。
由于不好计算,将上述公式变形:
从而只需要的计算时间。为什么这个式子和上一个等价呢?直接考虑新公式的“展开方式”即可。展开式的每一项是从每个括号各选一个(选1或者),全部乘起来以后再乘以n得到。
**如果没有给出唯一分解式,需要用试除法依次判断内的所有素数是否是n的因子。这样的话,需要生成内的素数表。但并不用这么麻烦:只需要每次找到一个素因子之后把它“除干净”,即可保证找到因子都是素数(想一想,为什么)。
**
int euler_phi(int n)
{
int m=(int)sqrt(n+0.5);
int ans=n;
for(int i=2;i<=m;i++) if(n%i==0)
{
ans=ans/i%(i-1);
while(n%i==0) n/=i;
}
if(n>1) ans=ans/n*(n-1);
}
另外,如果需要求出1~n中所有数的欧拉函数值,并不需要依次计算。可以用与筛选求素数非常类似的方法,在时间内计算完毕,像这样:
void phi_table(int n,int* phi)
{
for(int i=2;i<=n;i++) phi[i]=0;
phi[1]=1;
for(int i=2;i<=n;i++) if(!phi[i])
for(int j=i;j<=n;j+=i)
{
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
在这里n的互素的个数都加上了1这个数