码迷,mamicode.com
首页 > 其他好文 > 详细

欧拉函数

时间:2020-01-20 12:32:53      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:算法   inline   整数   lin   函数   线性   初始化   pre   容斥   

定义

\(\varphi(n)=n\cdot(1-\frac 1{p_1})\cdot(1-\frac 1{p_2})\cdot...\cdot(1-\frac 1{p_n})\)

其中\(p_i\)表示\(i\)的质因数

特别地,\(\varphi(1)=1\)

意义:对于正整数\(n\)\(\varphi(n)\)表示小于等于\(n\)的正整数中与\(n\)互素的数的数目

证明

用类似于容斥原理的方法求\(1\sim n-1\)中与\(n\)互素的数:

先把\(n\)的所有质因数\(p_i\)的倍数都筛掉,再把\(p_i,p_{i+1}\)的公共倍数添加回来,再去掉\(p_i,p_{i+1},p_{i+2}\)的公共倍数...

得到\(\varphi(n)=n-\frac n{p_1}-\frac n{p_2}-\cdots+\frac n{p_1p_2}+\frac n{p_2p_3}+\cdots\)

由相关数学知识化简得到定义式。

求解方法

  1. 由定义式可以得到一种直白的求法:(在线算法)

    用唯一分解定理的方法找出\(n\)的所有质因数,同时用定义式求即可

    由于\(p_i\)\(n\) 不同的质因数,所以计算中除法不会出现不能整除的情况

    为了防止爆精度,计算时先除后乘。

    int phi(int n) {
     if(n == 1) return 1;
     int p = n;
     for(int i=2, n1=n; i*i<=n1; i++) if(n%i == 0){
         p = p / i * (i-1);
         while(n%i == 0) n /= i;
     }
     if(n>1) p = p / n * (n-1);
     return p;
    }
  2. 打欧拉函数表:(离线算法)用筛法,边筛素数边算

    • 埃氏筛

      初始化\(phi[i]=i\)

      筛到素数\(p\),在标记\(p\)的倍数不是素数的同时计算,\(phi[i*p]=phi[i*p]/p*(p-1)\)

      void sieve(int n) {
         phi[1] = 1;
         for(int i=2; i<=n; i++) {
             if(!npr[i]) continue;
             for(int j=2; i*j<=n; j++) {
                 npr[i*j] = 1;
                 phi[i*j] = phi[i*j] / i * (i-1);
             }
         }
      }
    • 欧拉筛(线性筛)

      因为欧拉筛中每个数只筛一次,所以要一次算出最终结果。

      \(p\)为素数,分类讨论如下:

      1. \(phi[p]=p-1\)
      2. 已知\(phi[x]\)\(p\)能整除\(x\)\(phi[x*p]=phi[x]*p\)
      3. 已知\(phi[x]\)\(p\)不能整除\(x\)\(phi[x*p]=phi[x]*(p-1)\)

      简单证明:

      1. \(p\)以内所有数都与\(p\)互质,所以答案为\(p-1\)
      2. p是x的质因数,所以从定义式看从\(phi[x]\)\(phi[x*p]\)后面带括号部分是相同的,只是前面的\(x\)变成了\(x*p\)
      3. p不是x的质因数,所以\(p\)\(x*p\)新加入的质因数,所以前面的\(x\)变成\(x*p\)的同时后面要乘上因子\(\frac {p-1}p\),消去即相当于乘\(p-1\)
      void sieve(int n) {
         np = 0; phi[1] = 1;
         for(int i=2; i<=n; i++) {
             if(!npr[i]) p[++np] = i, phi[i] = i-1;
             for(int j=1; j<=np && i*p[j]<=n; j++) {
                 npr[i*p[j]] = 1;
                 phi[i*p[j]] = phi[i] * (i%p[j] ? p[j]-1 : p[j]);
                 if(i%p[j] == 0) break;
             }
         }
      }

欧拉函数

标签:算法   inline   整数   lin   函数   线性   初始化   pre   容斥   

原文地址:https://www.cnblogs.com/de-compass/p/12217440.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!