zoukankan      html  css  js  c++  java
  • 欧拉函数

    意义

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

    定义

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

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

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

    证明

    用类似于容斥原理的方法求(1sim 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)

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

    性质

    (a,b)互素时由定义式易证(varphi(acdot b)=varphi(a)cdotvarphi(b)),由此欧拉函数是积性函数。

    求解方法

    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*p)新增的素数,故由定义式知(phi[x])(phi[x*p])时后边带括号的部分相同,只是前面的(x)变成了(x*p),所以(phi[x]*p)即可
        3. (p)(x*p)新增的素数,由(phi[x])(phi[x*p])时要乘一个因子(frac{p-1}p),同时前面(x)变成(x*p),约分后为(phi[x]*(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;
        		}
        	}
        }
        

    参考博客

    【线性筛】-大米饼

  • 相关阅读:
    long和Long的区别
    C语言的变量的内存分配
    Java蓝桥杯 算法提高 九宫格
    Java实现 蓝桥杯算法提高金明的预算方案
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 三角形
    Java实现 蓝桥杯 算法提高 三角形
    Java实现 蓝桥杯 算法提高 三角形
    Java实现 蓝桥杯 算法提高 三角形
  • 原文地址:https://www.cnblogs.com/de-compass/p/12217440.html
Copyright © 2011-2022 走看看