• 欧拉函数


    意义

    对于正整数(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;
        		}
        	}
        }
        

    参考博客

    【线性筛】-大米饼

  • 相关阅读:
    Linux 信号量之Posix有名字的信号量
    Linux 读写锁
    linux 互斥锁和条件变量
    linux 线程基础
    linux 进程通信之 守护进程
    linux 进程通信之 信号
    linux 进程通信之 mmap
    linux 进程通信之 管道和FIFO
    form表单标签(非常重要,必须掌握)
    微信支付问题汇总
  • 原文地址:https://www.cnblogs.com/de-compass/p/12217440.html
Copyright © 2020-2023  润新知