Loading

[专题]数论: 线性筛欧拉函数

\[Designed\ By\ FrankWkd\ -\ Luogu@Lwj54joy,uid=845400 \]

引言:本文LateX较多,可能加载卡顿,请耐心等待.

关于Euler函数

  • \(Euler\) 函数,同时被称为欧拉函数, 定义: \(\varphi(n)\) 表示 \(\le n\) 且与 \(n\) 互质的数的个数
  • 我们规定:\(\varphi(1) = 1\)

Euler函数的性质

  • 积性:对于 \(gcd(a,b)=1\) 的两个数 \(a,b\) , $\varphi(a\times b)=\varphi(a)\times \varphi(b) $.
  • 欧拉反演:$\sum_{d|n}\varphi(d) = n $
  • 对于任意质数 \(p\)\(\varphi(p^k)=p^k-p^{k-1}\)

对于Euler函数性质的证明

  • 1:根据积性函数的定义可得。
  • 2:公式解释:对于每个是 \(n\) 的质因子的数 \(p\),把他们的 \(\varphi\) 全部加在一起的和是 \(n\).
    \(10\) 举例:\(10\) 的全部质因子为 \(\{2,3,5,7,9\}\) ,他们的 \(\varphi\)分别为: \(\{0,1,2,3,4\}\), 加起来就是原数 \(10\).
  • 3: 很显然,小于 \(p^k\) 的数中与 \(p\) 不互质的数仅有\(p,2p,3p\dots p^{k-1}p\).总数为 \(p^{k-1}\) 个.
    那小于它且与它互质的数的个数就是总数减去 \(p^{k-1}\) 个,即 \(\varphi(p^k)=\) 总数 \(-\ p^{k-1}\),即: \(\varphi(p^k)=p^k-p^{k-1}\)

求Euler函数

单个欧拉函数求法

  • 可以直接求出其唯一分解式然后求解(本人没太听懂,但是没关系,这一点用不到)

线性筛求Euler函数

  • 本文的重头戏来了!
  • 我们可以在线性筛求质数的同时求出每个数的Euler函数.\(p\)\(i\) 的最小质因子时,有三种情况:
    • 1: \(i\) 是质数: \(\varphi(i) = i-1\)
    • 2:\(p\)\(\frac{i}{p}\) 的质因子:\(\varphi(i)=p\times \varphi(\frac{i}{p})\)
    • 3: \(p\)\(\frac{i}{p}\)互质:$\varphi(i)=\varphi(p)\times \varphi(\frac{i}{p}) $.
  • 为什么要解决 \(\frac{i}{p}\)\(p\) 的关系呢?
    因为他们的乘积就是 \(i\) ,我们要求 \(\varphi(i)\),那么根据 \(Euler\) 函数的性质 \(1\) ,可以得出: \(\varphi(i)=\varphi(\frac{i}{p})\times \varphi(p)\) ,那么问题就变成了计算两个已知质数的 \(\varphi\) 的乘积.详见 板块【由数学到程序】

线性筛求Euler函数三种形式的证明

  • 1: 因为 \(i\) 为质数,由定义立得:\(\varphi(i) = i-1\)
  • 2: 设 \(i=p^kq\) ,其中 \(q\) 不含质因子 \(p\). 利用积性可得: \(\varphi(i)=\varphi(p^k)\times \varphi(q)\)
    利用 \(Euler\)函数性质三可得: \(\varphi(i)=\varphi(p^k) \times \varphi(q)=(p^k-p^{k-1})\times \varphi(q)\)
    提出公因式 \(p\) 可得: \(\varphi(i)=\varphi(p^k) \times \varphi(q)=(p^k-p^{k-1})\times \varphi(q)=p(p^{k-1}-p^{k-2})\times \varphi(q)\)
    \(Euler\) 函数性质三的逆运算可得: \(p(p^{k-1}-p^{k-2})\times \varphi(q)=p\times \varphi(p^{k-1})\times \varphi(q)\)
    \(Euler\) 函数性质一的逆运算可得: \(p(p^{k-1}-p^{k-2})\times \varphi(q)=p\varphi(p^{k-1})\times \varphi(q)=p\times \varphi(p^{k-1}\times q)\)
    根据除法的性质可得: \(p\times \varphi(p^{k-1}\times q)=p\times \varphi(\frac{i}{p})\)
    又因为 \(\varphi(i)=p\times \varphi(p^{k-1}\times q)\)
    所以得出: \(\varphi(i)=p\times \varphi(\frac{i}{p})\)
  • 3: 因为这二者互质,有积性立得: $\varphi(i)=\varphi(p)\times \varphi(\frac{i}{p}) $.
    OK,我们已经推完了数学部分!

由数学到程序

那么,如何应用到程序中呢?

  • 有几个条件:
    • 不同的量符合其性质(互质相等因数、大小关系等)
    • 等式成立。
  • 第一种情况非常简单,若 \(i\) 为质数,只要将他的 \(\varphi\) 设为 \(i-1\) 即可。在线性筛筛出质数时将它的 \(\varphi\) 设为其减一即可。
  • 第二、三种情况需要构造两个积为 \(i\) 的量,我们令他们分别为:\(p\)\(\frac{i}{p}\) 。因为 \(p\) 必须是 \(i\) 的最小质因子,所以它肯定是 \(primes\) 数组中的值,而且 \(i\) 由两个数的乘积构成,所以是合数。那线性筛中哪里可以筛除合数呢?双层 \(for\) 中!那么,我们已经确定了大致位置。
  • 情况二:

线性筛筛Euler函数代码(还没写完)

点击查看代码
#include <bits/stdc++.h>
int primes[101000], n, phi[101000]; //分别存储:素数,数据总数,i的欧拉函数
bool f[101000];//标记当前数是不是素数
void get_phi() {//设p是i的最小质因子,p为质数
	int cnt = 0;
	phi[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!f[i]) {
			primes[++cnt] = i;
			phi[i] = i - 1; //对应情况一
		}
		for (int j = 1; j <= cnt and primes[j]*i <= n; j++) {
			f[i * primes[j]] = true;
			
			
			/*在此for循环中,i的定义发生了转移,由var_i*primes[j]来表示i,
			那么var_i与primes[j]就理所当然地成为了i的因子。
			由于primes[j]不可能比var_i更大(因为大于i的质数还没筛到)s
			所以primes[j]符合公式中p的定义。
			而var_i呢?它很被动,必须保证与p的乘积为i,所以干脆把var_i在数学公式中定义为i/p
			*/
			if (i % primes[j] == 0) {
				phi[i * primes[j]] = phi[i] * primes[j];
				break;
			}else{
				phi[i * primes[j]] = phi[i] * phi[primes[j]];
			}
		}
	}
}

int main() {
	std::cin >> n;
	get_phi();
	for(int i = 1;i <= n;i++){
		std::cout<<phi[i]<<std::endl;
	}
}

posted @ 2025-01-22 18:25  FrankWkd  阅读(124)  评论(0)    收藏  举报