数论中的计数问题(含欧拉函数)

版权声明:个人笔记,仅供复习 https://blog.csdn.net/weixin_42373330/article/details/82844028

唯一分解定理

  • 算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。(这个定理真的是有趣

约数的个数


描述:

给出正整数n的唯一分解式n=\small {p_{1}}^{a1}{p_{2}}^{a2}{p_{3}}^{a3}...{p_{k}}^{ak},求n的正整数的个数。

分析:

不难看出,n的任意正约数也只能包含p1,p2,p3等素因子,而不能有新的素因子出现。对于n的某个素因子\small {p_{i}}^{},它在所求约数中的指数可以是0,1,2,···,\small {a_{i}}^{}\small {a_{i}}^{}+1种情况,而且不同的素因子之间相互独立。根据乘法原理,n的正约数个数为:

\small \prod_{i=1}^{k}(a_{i}+1)=(a_{1}+1)(a_{2}+1)...(a_{k}+1)

小于n且与n互素的个数


描述:

给出正整数n的唯一分解式n=\small {p_{1}}^{a1}{p_{2}}^{a2}{p_{3}}^{a3}...{p_{k}}^{ak},求1,2,3,···,n中与n互素的数的个数。

分析:

用容斥原理。首先从总数n中分别减去p1,p2,···,·pk的倍数(对于素数p来说,“与p互素”和“不是p的倍数等价”),即\small n-\frac{n}{p_{1}}-\frac{n}{p_{2}}-...-\frac{n}{p_{k}},然后加上“同时是两个素因子的倍数”的个数\small \frac{n}{p_{1}p_{2}}+\frac{n}{p_{1}p_{3}}+...+\frac{n}{p_{k-1}p_{k}},再减去“同时是3个素因子的倍数”——写成一个“学术味比较浓”的公式就是:

                                                \small \varphi (n)=\sum_{S\subseteq \left \{ p1,p2,... \right.\left. ,pk \right \}}^{}\small (-1)^{\left | S \right |}\frac{n}{\prod_{p_{i}\in S}^{p_{i}}},
这里引入的新记号\small \varphi (n)就是题目中所求的结果,称为欧拉函数。强烈建议初学者花一些时间理解这个公式(也是对自己说的)。对于{p1,p2,···,pk}的任意子集S,“不与其中任何一个互素”的元素个数是\small \frac{n}{\prod_{p_{i}\in S}^{p_{i}}}。不过这一项的前面是加号还是减号呢?这取决于S中的元素个数——奇数个就是“减号”,偶数个是“加号”。

由于不好计算,将上述公式变形:

                                                  \small \varphi(n)=n(1-\frac{1}{p_{1}})(1-\frac{1}{p_{2}})...(1-\frac{1}{p_{k}})

从而只需要\small O(k)的计算时间。为什么这个式子和上一个等价呢?直接考虑新公式的“展开方式”即可。展开式的每一项是从每个括号各选一个(选1或者\small -\frac{1}{p_{i}}),全部乘起来以后再乘以n得到。

**如果没有给出唯一分解式,需要用试除法依次判断\small \sqrt{n}内的所有素数是否是n的因子。这样的话,需要生成\small \sqrt{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中所有数的欧拉函数值,并不需要依次计算。可以用与筛选求素数非常类似的方法,在\small O(nloglogn)时间内计算完毕,像这样:

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这个数

 

猜你喜欢

转载自blog.csdn.net/weixin_42373330/article/details/82844028
今日推荐