zoukankan      html  css  js  c++  java
  • 欧拉定理+欧拉筛选法

    一、概念

    互质关系

    如果两个整数(或者两个以上的整数)的最大公约数是1,则称他们为互质。也就是说两个整数,除了1以外,没有其它的最大公约数了,这两个整数就叫做互质关系。
    比如说7,11他们的最大公约数只有1,所以他们互质;8,10他们的最大公约数为1,2,所以这两数不是互质关系。

    欧拉函数

    欧拉函数φ(n)是小于或等于n的正整数中与n互质的数的数目,称为欧拉函数
    比如说当n=8时,与8能形成互质关系的数有4个,分别是1,3,5,7,所以φ(8)=4
    具体φ(n)函数的计算公式,可以分为以下四种情况:

    情况一: 当n=1,φ(1)=1

    因为1与任何整数都是互质关系,所以当n=1时,φ(1)=1

    情况二:当n为质数,φ(n)=n-1

    因为质数与小于它的每一个数,都构成互质关系,所以当n为质数时,φ(n)=n-1 。
    比如说n=3时,1,2都跟他是互质关系, n=7时,1,2,3,4,5,6都跟他是互质关系。

    情况三:n = p^k (p为质数,k为指数,且大于等于1),n是质数的k次方,则φ(p^k) = p^k - p^(k-1) = p^k(1 - 1/p)

    比如:φ(8) = φ(2^3) = 2^3 - 2^2 = 4
    φ(27) = φ(3^3) = 3^3(1 - 1/3) = 18

    情况四: n是两个互质的整数之积,如:n = p1 * p1,则 φ(n) = φ(p1p2) = φ(p1)φ(p2)

    比如:φ(56)=φ(8×7)=φ(8)×φ(7)=4×6=24

    二、定理

    同余定理

    给定一个正整数n,如果两个整数a和b满足a-b能够被n整除,即(a-b)/n得到一个整数,那么就称整数a与b对n同余,记作a≡b(mod n)。这就是同余定理
    例如:26≡2(mod 12), 26%12 余2, 2%12余2, 26-2/12 = 0,所以26与2对模12同余

    欧拉定理

    在数论中,欧拉定理是一个关于同余的性质。欧拉定理表明,若n,a为正整数,且n,a互素(即gcd(a,n)=1),则

    a^{varphi(n)} equiv 1 pmod n



    a^{varphi(n)}与1在模n下同余;varphi(n)为欧拉函数。

    首先看一个基本的例子。令a = 3,n = 5,这两个数是互素的。比5小的正整数中与5互素的数有1、2、3和4,所以varphi(5)=4。计算:a^{varphi(n)} = 3^4 = 81,而81 equiv 80 + 1 equiv 1 pmod{5}。与定理结果相符。

    这个定理可以用来简化幂的模运算。比如计算7^{222}的个位数,实际是求7^{222}被10除的余数。7和10互素,且varphi(10)=4。由欧拉定理知7^4equiv 1pmod {10}。所以  7^{222}= 7^{4cdot 55+2}= (7^4)^{55}cdot 7^2equiv 1^{55}cdot 7^2equiv 49equiv 9pmod{10}      //欧拉函数φ(n)的作用就是把ap表示成aφ(n)*x+y
    一般地,在简化幂的模运算的时候,(当a和n互素) 我们要对a的指数取模varphi(n)

    xequiv y pmod {varphi(n)},则a^x equiv a^y pmod n

    三、求欧拉函数varphi(n)

    一、直接法

    原理:

    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的整数。euler(1)=1(唯一和1互质的数就是1本身)。

    //直接法
    int euler(int n)
    {
      int res=n,a=n;
      for(int i=2;i*i<=a;i++)
      {
        if(a%i==0)
        {
          res=res/i*(i-1);
          while(a%i==0)
            a=a/i;
        }
      }
      if(a>1)
        res=res/a*(a-1);
        return res;
      }
     

    二、欧拉筛选法

    i表示当前做到的这个数,prime[j]表示当前做到的质数,那要被筛掉的合数就是i*prime[j]。若prime[j]在这个合数里只出现一次(i%prime[j]!=0),也就是i和prime[j]互质时,则根据欧拉函数的积性函数的性质,phi[i * prime[j]]=phi[i] * phi[prime[j]]。若prime[j]在这个合数里出现了不止一次(i%prime[j]=0),也就是这个合数的所有质因子都在i里出现过,
    那么根据公式,φ(i * prime[j])=φ(i) *prime[j]。复杂度为O(n)。其中得到的prime[n]是1~n的所有质数
    void euler(int n)
    {
        phi[1]=1;//1要特判 
        for (int i=2;i<=n;i++)
        {
            if (flag[i]==0)//这代表i是质数 
            {
                prime[++num]=i;
                phi[i]=i-1;
            }
            for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
            {
                flag[i*prime[j]]=1;//先把这个合数标记掉 
                if (i%prime[j]==0)
                {
                    phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
                    break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
                }
                else phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
            }
        }
    }

    三、另一种更简洁的筛选法、推荐

    const int maxn = 1e6+10;
    int prim[maxn], w[maxn], cnt = 0;//prim[i]起标记作用,prim[i]==0表示i是质数,注意这里把1也标记成了质数
    int x[maxn];//x[i]表示偶数是i的符合条件的两个质数是x[i]和i-x[i];
    void init()
    {
      memset(prim, false, sizeof(prim));
      prim[1]=1;//1不是素数
      for(int i = 2; i < maxn; i++)
      {
        if(prim[i]) //判断i是否为偶数
          continue;
        w[cnt++] = i;//w存质数
        for(int j = i << 1; j < maxn; j+=i)//把所有质数的倍数标记
         prim[j] = true;
      }
      
    }

     欧拉公式的延伸:小于n的且与n互质的数的和是euler(n)*n/2


    来源:CSDN
    原文:https://blog.csdn.net/u012861385/article/details/24271435

    链接:https://www.jianshu.com/p/9007f61e27a8
    來源:简书

     

  • 相关阅读:
    CF991D Bishwock
    CF1010D Mars rover
    NOIP 2011 计算系数
    SDOI 2008 仪仗队
    浅谈欧拉函数
    CF1249F Maximum Weight Subset
    NOIP 2011 铺地毯
    CF707D Persistent Bookcase
    C++ STL bitset 容器详解
    CF798D Mike and distribution
  • 原文地址:https://www.cnblogs.com/-citywall123/p/10066464.html
Copyright © 2011-2022 走看看