欧拉函数求和

题目:

给出给定正整数n,求\sum_{i=1}^{n}f(i),此处f(n)定义为小于等于n并且与n互质的数的个数(此处认为1与1互质)。

所谓的f(n)就是欧拉函数\phi (n),只是对1做了一下重新定义,整体不影响。

题目求的是从1到n的所有欧拉函数的和

如何求欧拉函数,可以看这个前几天才写的

但是逐个求欧拉函数毫无疑问时间会爆的。

如果能知道欧拉函数的一些性质,特别是这个:

如果a和b互质,则f(a*b)=f(a)*f(b);

那想必马上就能想到要用动态规划求解

我们现在想一个for循环,i从2到n,如何构建向前的递推式?

因为i本身不一定是质数,那什么数肯定和i互质?当然是质数,那么遍历小于i的质数肯定能找到和i互质的数了。然后相乘递推。

由于质数是共用的,所以可以开一个全局数组来储存质数,如果i本身是质数,则把i加入到质数的数组中,这样质数数组也随着i的循环而逐渐增加

直觉觉得这样好像会漏数,但实际上不会。如果一个数是质数,它会被加到质数数组里,而一个合数肯定可以写成许多质数的乘积。

来看一下代码

其中primer是质数数组,judge[i]用来判断i是否是质数,phi[i]即是欧拉函数,cnt是primer数组的大小,sum是欧拉函数的求和值。

#include<iostream>
using namespace std;
#define int long long
const int N=1e6+7;
int primer[N],judge[N],phi[N],n,sum,cnt=0;
void getphi(int n){
    phi[1]=1;
    for(int i=2;i<=n;i++){
        if(!judge[i]){//judge[i]==false代表当前i是质数
            primer[cnt++]=i;
            phi[i]=i-1;
        }
        for(int j=0;primer[j]*i<=n;j++){
            judge[primer[j]*i]=true;
            if(i%primer[j]==0){
            phi[i*primer[j]]=primer[j]*phi[i];
            break;
            }
            else phi[i*primer[j]]=(primer[j]-1)*phi[i];
        }
    }
}
signed main()
{
    cin>>n;
    getphi(n);
    for(int i=1;i<=n;i++)
    sum+=phi[i];
    cout<<sum;
    return 0;
}

if(!judge[i])需要配合judge[primer[j]*i]=true来看

我们在向后递推的时候,i*primer[j]的值肯定是个合数,那么judge[i*primer[j]]赋值成true标记它为合数。

因为我们是向后递推,遍历到i的时候phi(i)如果算好了,那么judge[i]肯定是true了,那i肯定就不是质数。如果i是质数,那么phi(i)就没有赋值,因为i是质数,phi(i)=i-1;

        if(i%primer[j]==0){
            phi[i*primer[j]]=primer[j]*phi[i];
            break;
            }
        else phi[i*primer[j]]=(primer[j]-1)*phi[i];

这段代码是最重要的,我们知道i肯定可以写成i=p^{n}*q^{m}...(p,q等都是质因数,n,m是指数)的形式,这个if else语句相当于找到   i   乘上   所有   小于等于   i的最小质因数   的质数   的积,然后求出这个乘积的欧拉函数

这样会不会漏数?我举个例子先说明一下

比如i=15,它是3*5,那么质数到3就结束了,最后求了30和45的欧拉函数,有人会问那5没遍历到的话75的欧拉函数是怎么来的?

实际上在i=25的时候,它在质数遍历到3的时候还没结束呢,这时候就会求出75的欧拉函数了。

这实际上是线性筛的思想,一个数只被它的最小质因数标记,每个数只有一个最小质因子,所以每个数都只会筛一遍。想要了解的话可以自行学习。

总而言之,这样是不会漏数的。

但问题是i如果是当前质数的倍数,欧拉函数该怎么算?

我们知道欧拉函数的计算是看质因数的,设m=i*primer[j],实际上m的质因数不用找了,就是i的质因数,因为primer[j]是i的因数,primer[j]的所有质因数当然也被包括在i的质因数里。公式\phi (m)=m(1-\frac{1}{p})*(1-\frac{1}{q})...          m后面的部分        \phi (i)=i(1-\frac{1}{p})*(1-\frac{1}{q})...i后面的部分是完全一样的,而i*primer[j]=m,所以f(m)=primer[j]*f(i);

而如果i不是当前质数的倍数,那么i和primer[j]互质,那就是最简单的公式了

综上,整个代码就写完了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值