欧拉函数模板及拓展

在数论,对正整数n,欧拉函数是 小于 n的正整数中与n互质的数的数目(φ(1)=1)。此函数以其首名研究者欧拉命名(Euler’s totient function),它又称为Euler’s totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。
其中1的欧拉函数φ(1)=1

欧拉公式的延伸:对于一个数,与其互质的数的总和是euler(n) × n/2。
如φ(15)=8,有互质数 1,2,4,7,8,11,13,14,加和后结果为60,而8 × 15/2结果同为60。
通常用phi表示欧拉函数或存储欧拉函数的数组

特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[a × b]=phi[b] × a【 b是 质数a 的倍数则a × b的欧拉函数是b的欧拉函数的a倍 φ(a × b)=φ(b) × a】
3.若a,b互质,phi[a × b]=phi[a] × phi[b]【当a为质数时,if (b mod a)!=0 ,phi[a × b]=phi[a] × phi[b]】
4.特殊性质:当n为奇数时,φ(2n)=φ(n)

*φ(1) = 1
*φ(2) = 1
*φ(3) = 2
*φ(4) = 2
φ(5) = 4
*φ(6) = 2
φ(7) = 6
φ(8) = 4
φ(9) = 6
φ(10) = 4
φ(11) = 10
φ(12) = 4
φ(13) = 12
φ(14) = 6
φ(15) = 8
φ(16) = 8
φ(17) = 16
φ(18) = 6
φ(19) = 18
φ(20) = 8
φ(21) = 12
φ(22) = 10
φ(23) = 22
φ(24) = 8
φ(25) = 20
φ(26) = 12
φ(27) = 18
φ(28) = 12
φ(29) = 28
φ(30) = 8
φ(31) = 30
φ(32) = 16
φ(33) = 20
φ(34) = 16
φ(35) = 24
φ(36) = 12
φ(37) = 36
φ(38) = 18
φ(39) = 24
φ(40) = 16
φ(41) = 40
φ(42) = 12
φ(43) = 42
φ(44) = 20
φ(45) = 24
φ(46) = 22
φ(47) = 46
φ(48) = 16
φ(49) = 42
φ(50) = 20

可以发现只有φ(1),φ(2),φ(3),φ(4),φ(6)是质数,其余所有欧拉函数都是合数。

Euler函数表达通式:euler(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数,x是不为0的整数。

log(n)单个数字求解欧拉函数模板:

int phi(int n)
{
    int ans=n,tmp=n;
    for(int i=2; i*i<=tmp; i++)     ///遍历所有质因子,其中tmp遍历范围因为去除了质因子的倍数一直在变小
    {
        if(tmp%i==0)
        {
            ans=ans/i*(i-1);        ///此处是x*(1-1/p1)=x*(p1-1)/p1,为防止溢出,先计算除法
            while(tmp%i==0)tmp/=i;  ///去除质因子倍数
        }
    }
    if(tmp>1)ans=ans/tmp*(tmp-1);
    return ans;
}

nlog(n)打表欧拉函数:

const int MAXN=100005;
int euler[MAXN];
void Init()
{
    euler[1]=1;
    for(int i=2;i<MAXN;i++) euler[i]=i;
    for(int i=2;i<MAXN;i++)
    {
        if(euler[i]==i)
        {
            for(int j=i;j<MAXN;j+=i)
            {
                euler[j]=euler[j]/i*(i-1);
            }
        }
    }
    for(int i=1;i<=50;i++)printf("φ(%d) = %d\n",i,euler[i]);
}

O(n)线性筛打表欧拉函数(1s内可以打表2e7的欧拉函数):

LL euler[maxn]={0};///欧拉函数
LL prime[maxn],cnt=0;///素数
bool vis[maxn];
void Init()///线性欧拉筛
{
    euler[1]=1;
    memset(vis,false,sizeof vis);
    for(int i=2;i<maxn;i++)
    {
        if(!vis[i])prime[++cnt]=i,euler[i]=i-1;///素数情况
        for(int j=1;j<=cnt&&i*prime[j]<=maxn;j++)
        {
            vis[i*prime[j]]=1;///素数倍数非素数
            if(i%prime[j])euler[i*prime[j]]=euler[i]*(prime[j]-1);
            else
            {
                euler[i*prime[j]]=euler[i]*prime[j];
                break;
            }
        }
//        printf("φ(%d)=%lld\n",i,euler[i]);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值