欧拉函数性质

https://blog.csdn.net/yxuanwkeith/article/details/52387873
 
数论学习笔记 欧拉函数 (一些性质和运用)内置杜教筛

定义

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

一些欧拉函数的性质

性质一

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

性质二

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

性质三

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

性质四

设n=pk11∗pk22...∗pkmm ,则φ(n)=n∗(1−1p1)∗(1−1p2)∗...(1−1pm)
证明:
根据性质二

φ(n)=∏(pi−1)pki−1i(pi|n)=n∏(1−1p1)(直接把n提出来)


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

性质五

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

      2. 若i≠j ,那么a∗pimodn≠a∗pjmodn
      反证:
           假如a∗pimodn=a∗pjmodn ,设a∗pi=ki∗n+b
           那么

a∗pi=ki∗n+b=a∗pj=kj∗n+ba∗(pi−pj)=n∗(ki−kj)


           因为a与n互质,即n|(pi−pj) ,不成立。
所以S=Z 。
由此我们可以列出等式:

a∗p1∗a∗p2...∗a∗pφ(n)aφ(n)≡p1∗p2...pφ(n)(modn)≡1(modn)

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

性质六

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

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

性质七

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

k2b+n=k1bn=(k1−k2)b


      所以gcd(n,m)至少等于b 。
      得证。

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

性质八

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

∑i=1ni=∑i=1n∑d|iφ(d)=∑d=1nφ(d)∗⌊nd⌋


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

信息学中的应用

应用一:线筛φ 函数

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

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

//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),第三种情况
        }
    }
}

应用二: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;
}

应用三:杜教筛求φ 的前缀和

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

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

∑i=1n(f∗g)(i)=∑i=1n∑d∣ig(d)f(id)=∑d=1ng(d)∑1≤i≤n,d|if(id)=∑d=1ng(d)∑1≤i≤⌊nd⌋f(i)=∑d=1ng(d)S(⌊nd⌋)

∴g(1)S(n)=∑i=1n(f∗g)(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=1n⎛⎝i−∑d|i,d<iφ(d)⎞⎠=n⋅(n+1)2−∑i=2n∑d|i,d<iφ(d)=n⋅(n+1)2−∑id=2n∑d=1⎢⎣⎢⎢nid⎥⎦⎥⎥φ(d)=n⋅(n+1)2−∑i=2n∑d=1⌊ni⌋φ(d)=n⋅(n+1)2−∑i=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. f(i)=φ(i)∗i ,f(i)∗id=id2

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


这个可以扩展到f(i)=φ(i)∗ik ,f(i)∗idk=idk+1

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YxuanwKeith/article/details/52387873
个人分类: 算法-数论
 

 

想对作者说点什么? 我来说一句
 

posted on 2018-05-17 10:56  比特飞流  阅读(656)  评论(0)    收藏  举报

导航