【数学】Euler函数

Euler函数的定义:小于等于n的与n互质的正整数的个数,或者小于n的与n互质的自然数的个数。这两个结果都是指向 gcd(0,1)=1 也就是说 φ(1)=1

φ(p)=p1
φ(pk)=pkpk1=pk1(p1) 就是 pk 里面去除掉所有的 p 的倍数。
合数的情况使用积性函数的性质求出,或者用 φ(n)=nt=1(11pt) 也就是n乘以1-每种质数的倒数。

事实上,设 n=t=1ptkt ,则 φ(n)=t=1φ(ptkt)=t=1ptktpt1pt=nt=1pt1pt

Euler函数可以用来给Fermat小定理升级成Euler定理

gcd(a,m)=1 ,则 aφ(m)1(modm)

Euler函数是积性函数。

Dirichlet卷积

n=d|nφ(d)

也就是每个数=它所有因子的Euler函数之和。

注意积性函数的Dirichlet卷积也是积性函数,同时,Dirichlet卷积是积性函数的函数自己也是积性函数。

质因数分解法求Euler函数

copyconst int MAXN = 1e6 + 10;
int p[MAXN], ptop;
int pm[MAXN];

void sieve(int n) {
    pm[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!pm[i])
            p[++ptop] = i, pm[i] = i;
        for(int j = 1; j <= ptop; ++j) {
            int t = i * p[j];
            if(t > n)
                break;
            pm[t] = p[j];
            if(i % p[j])
                ;
            else
                break;
        }
    }
}

int phi(int n) {
    int res = n;
    for(int i = 1; p[i]*p[i] <= n; ++i) {
        if(n % p[i] == 0) {
            res = res / p[i] * (p[i] - 1);
            while(n % p[i] == 0)
                n /= p[i];
        }
    }
    if(n > 1)
        res = res / n * (n - 1);
    return res;
}

时间复杂度为 O(n) 预处理质数,然后 O(nlogn) 单次求解Euler函数。

无论如何都要先筛质数,省掉这个log。

线性筛法求Euler函数

copyconst int MAXN = 1e6 + 10;
int p[MAXN], ptop;
int pm[MAXN], pk[MAXN], phi[MAXN];

void sieve(int n) {
    memset(pm, 0, sizeof(pm[0]) * (n + 1));
    ptop = 0, pm[1] = 1, pk[1] = 1, phi[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!pm[i]) {
            p[++ptop] = i, pm[i] = i;
            pk[i] = i, phi[i] = i - 1;
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; ++j) {
            pm[t] = p[j];
            if(i % p[j]) {
                pk[t] = pk[p[j]];
                phi[t] = phi[i] * phi[p[j]];
            } else {
                pk[t] = pk[i] * p[j];
                phi[t] = (pk[t] == t) ? t - t / p[j] : phi[t / pk[t]] * phi[pk[t]];
                break;
            }
        }
    }
}

杜教筛求Euler函数前缀和

posted @   purinliang  阅读(1098)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示