欧拉函数 (一些性质和运用)内置杜教筛

定义

在数论中,对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目。并且用符号 φ(n) 表示一个整数的欧拉函数。例如 φ(8)=4 。特殊的 φ(1)=1

一些欧拉函数的性质

性质一

对于一个质数n, φ(n)=n1 。 
证明: 
因为n是质数。

性质二

若P是质数, n=pk ,则 φ(n)=pkpk1=(p1)pk1 。 
证明: 
因为除了p的倍数外,其他数都跟n互质。

性质三

gcd(n,m)=1 时, φ(nm)=φ(n)φ(m)  
证明: 
φ(n) 是积性函数。

性质四

n=pk11pk22...pkmm ,则 φ(n)=n(11p1)(11p2)...(11pm)  
证明: 
根据性质二 

φ(n)=(pi1)pki1i(pi|n)=n(11p1)(n)

当然也可以用容斥的想法去理解。

性质五

欧拉定理:对于互质的整数 a,m aφ(m)1(modm) 。 
证明: 
这小于n且与n互质的集合时 Z ,显然 |Z|=φ(n) Z= { p1,p2...pφ(n) }。 
令集合 S= { ap1modn,ap2modn...apφ(n)modn }。 
因为: 
      1. 因为 a n 互质, pi n 互质,所以 api n 互质,所以 ap1modnZ

      2. 若 ij ,那么 apimodnapjmodn  
      反证: 
           假如 apimodn=apjmodn  ,设 api=kin+b  
           那么 

api=kin+b=apj=kjn+ba(pipj)=n(kikj)

           因为a与n互质,即 n|(pipj) ,不成立。 
所以 S=Z 。 
由此我们可以列出等式: 
ap1ap2...apφ(n)aφ(n)p1p2...pφ(n)(modn)1(modn)

延伸: 
费马定理:如果正整数a与p互质,则 ap11(modp) 。 
证明:由性质一可得 φ(p)=p1 ,代入欧拉定理即可

性质六

设小于n的所有与n互质的数的和为 Sum Sum=nφ(n)2  
证明: 
      首先证明一个结论:如果 gcdn,i=1 gcdn,ni=1 。 
      反证法:如果存在 k1 使 gcdn,ni=k ,那么 
      (ni)modk=0 nmodk=0  
      可得 imodk=0 ,即 gcdn,i=k ,也就是说如果 gcdn,i=1 ,那么 gcdn,ni1

那么就可以得知与n互质的数都是成对存在的,并且和为n,那么就可以得出 Sum=nφ(n)2 的公式。

性质七

首先 p 是个质数。如果 imodp=0 ,那么 φ(ip)=pφ(i) (结论一),否则 φ(ip)=φ(i)(p1) (结论二)。 
证明: 
对于第一个结论我们只需证明 gcd(n,m)=1 可以得出 gcd(n,m+n)=1 即可。 
      反证法:假设 gcd(n,m+n)=b(b1) 。设 n+m=k1b,m=k2b 。 

k2b+n=k1bn=(k1k2)b

      gcd(n,m)b 。 
      得证。

对于第二个结论,我们可知由于 gcd(i,p)=1 φ(ip)=φ(p)φ(i) ,并且 φ(p)=p1 (性质一,性质三),得证。

性质八

直接给式子吧… 
n=d|nφ(d)  
根据上面那条式子可以继续推点显而易见的东西 

i=1ni=i=1nd|iφ(d)=d=1nφ(d)nd

反演一下, φ(n)=d|nμ(d)nd

信息学中的应用

应用一:线筛 φ 函数

这个算法让我们可以在 O(n) 的时间得出 φ(1) ~ φ(n) 的值。 
首先我们要用到几条上面提到的性质。 
      1.  φ(n)=n1 (性质一) 
      2. 如果 imodp=0 ,那么 φ(ip)=pφ(i) (性质七) 
      3. 如果 imodp0 ,那么 φ(ip)=φ(i)(p1) (性质七)

那么根线筛素数的原理一样(积性函数)我们只需根据欧拉函数的性质来进行线筛。

//YxuanwKeith
void Getphi(int Max) {
    phi[1] = 1;
    for (int i = 2; i <= Max; i ++) {
        if (!Flag[i]) {
            phi[i] = i - 1; // i是质数,第一种情况。
            pri[++ pri[0]] = i;
        }
        for (int j = 1; j <= pri[0]; j ++) {
            if (1ll * i * pri[j] > Max) break;
            Flag[i * pri[j]] = 1; //筛质数。
            if (i % pri[j] == 0) {
                phi[i * pri[j]] = phi[i] * pri[j];//(i % pri[j] = 0),第二种情况
                break;
            }
            phi[i * pri[j]] = phi[i] * (pri[j] - 1); //(i % pri[j] != 0),第三种情况
        }
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
应用二: O(n) 得到 φ(n)

直接根据性质四, O(n) 的枚举 n 的所有质因子,然后直接套用公式算,如果 n 特别打的话还可以选择用 millerrabin+pollarrho 来找质数。

//YxuanwKeith
long long Getphi(long long n) {
    long long phi = n;
    for (long long i = 2; i * i <= n; i ++) {
        if (n % i == 0) {
            phi /= i;
            phi *= i - 1;
            while (n % i == 0) n /= i;
        }
    }
    if (n != 1) phi /= n, phi *= n - 1;
    return phi;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
应用三:杜教筛求 φ 的前缀和

即求 ni=1φ(i)n<=1010  
51nod题目连接

由于本文着重讨论欧拉函数的性质,所以就不细讲杜教筛相关内容,有兴趣的可以通过下面的blog了解: 
http://blog.csdn.net/skywalkert/article/details/50500009 
基本原理:假设我们要计算 S(n)=ni=1f(i)  

i=1n(fg)(i)=i=1ndig(d)f(id)=d=1ng(d)1in,d|if(id)=d=1ng(d)1indf(i)=d=1ng(d)S(nd)

g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(ni)

根据杜教筛的应用,设 f(i)=φ(i) ,我们要找到一个函数 g(i) 使得 g(i) 的前缀和和 f(i)g(i) 的前缀和都很好求。根据性质八,不难发现 f(i)1=id 1 函数满足各项都为1, id 函数满足 id(i)=i )。 
ϕ(n)=ni=1φ(i) ,根据杜教筛: 

ϕ(n)=i=1nφ(i)=i=1nid|i,d<iφ(d)=n(n+1)2i=2nd|i,d<iφ(d)=n(n+1)2id=2nd=1nidφ(d)=n(n+1)2i=2nd=1niφ(d)=n(n+1)2i=2nϕ(ni)

然后递推进去算就可以了,直接这样算是 O(n34) ,但是由于 φ 是积性函数,可以预处理出前 n23 ϕ 然后再做杜教筛,复杂度就优化成了 O(n23)

//YxuanwKeith
//51nod1239
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long LL;

const int MAXN = 5e6 + 5, MAXM = 1e6 + 5;
const int Mo = 1e9 + 7;

LL n, que[MAXM];
int m, num, pri[MAXN], sum[MAXN], phi[MAXN], ids[MAXM], idl[MAXM], s[MAXM], inv[MAXN];
bool flag[MAXN];

int power(int x, int y) {
    int ans = 1;
    for (; y; y >>= 1, x = 1ll * x * x % Mo)
        if (y & 1) ans = 1ll * ans * x % Mo;
    return ans;
}

void prepare() {
    phi[1] = 1;
    for (int i = 2; i < MAXN; i ++) {
        if (!flag[i]) pri[++ pri[0]] = i, phi[i] = i - 1;
        for (int j = 1; j <= pri[0] && 1ll * i * pri[j] < MAXN; j ++) {
            int x = i * pri[j];
            flag[x] = 1;
            if (i % pri[j] == 0) {
                phi[x] = phi[i] * pri[j];
                break;
            }
            phi[x] = phi[i] * (pri[j] - 1);
        }
    }
    for (int i = 1; i < MAXN; i ++) sum[i] = (sum[i - 1] + phi[i]) % Mo;
}

int main() {
    scanf("%lld", &n);
    prepare();
    m = sqrt(n);
    for (LL l = 1; l <= n; l ++) {
        LL d = n / l, r = n / d;
        que[++ num] = d;
        if (d <= m) ids[d] = num; else idl[l] = num;
        l = r;
    }
    int inv = power(2, Mo - 2);
    for (int i = num; i; i --) {
        LL x = que[i];
        if (x < MAXN) s[i] = sum[x]; else {
            int y = x % Mo;
            s[i] = 1ll * y * (y + 1) % Mo * inv % Mo;
            for (LL l = 2; l <= x; l ++) {
                LL p = x / l, r = x / p;
                p = (p <= m) ? ids[p] : idl[n / p];
                (s[i] -= 1ll * (r - l + 1) * s[p] % Mo) %= Mo;
                l = r;
            }

        }
    }
    printf("%d\n", (s[1] + Mo) % Mo);
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

另外还有一些欧拉函数的变形也可以通过杜教筛来算: 
1.  f(i)=φ(i)i f(i)id=id2  

d|ndφ(d)nd=nd|nφ(d)=n2

这个可以扩展到 f(i)=φ(i)ik f(i)idk=idk+1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值