欧拉函数(复习自用笔记)

复习资料来源:刘汝佳.<<算法竞赛入门>>系列
欧拉函数描述为 ϕ ( n ) = 小 于 n 且 与 n 互 素 的 数 字 个 数 \phi(n)=小于n且与n互素的数字个数 ϕ(n)=nn.
如 何 求 得 欧 拉 函 数 呢 , 首 先 运 用 容 斥 定 理 求 . 如何求得欧拉函数呢,首先运用容斥定理求. ,.
n = p 1 a 1 ∗ p 2 a 2 . . p 3 a 3 n=p_1^{a1}*p_2^{a2}..p_3^{a3} n=p1a1p2a2..p3a3
那么先减去包含 p 1 , p 2 , p 3 p1,p2,p3 p1,p2,p3倍数的个数.
n − ( n / p 1 ) − ( n / p 2 ) . . − ( n / p k ) n-(n/p1)-(n/p2)..-(n/p_k) n(n/p1)(n/p2)..(n/pk)
再加上同时包含 p 1 p 2 , p 1 p 3 , p 2 p 3.. 等 含 两 个 因 子 的 个 数 p1p2,p1p3,p2p3..等含两个因子的个数 p1p2,p1p3,p2p3..
+ ( n / ( p 1 ∗ p 2 ) ) + ( n / ( p 1 ∗ p 3 ) . . +(n/(p1*p2))+(n/(p1*p3).. +(n/(p1p2))+(n/(p1p3)..
然后再减去含有三个因子的个数…
ϕ ( n ) = ∑ S ⊆ p 1 , p 2.. p k ( − 1 ) ∣ S ∣ ∗ n ∏ p i ⊂ s p i \phi(n)=\sum_{S\subseteq{p1,p2..pk}}(-1)^{|S|}*{n\over \prod_{pi\subset s}pi} ϕ(n)=Sp1,p2..pk(1)Spispin.
紫书上提供的式子,看起来十分别扭,也难以计算.
考虑重新组合上述式子.实际上类似于二项式计算.可以认为每一个 p p p都是由 ( 1 − 1 p i ) 相 乘 组 合 而 成 (1-{1\over p_i})相乘组合而成 (1pi1)
所以有:
ϕ ( x ) = n ∗ ∏ ( 1 − 1 p i ) \phi(x)=n*\prod(1-{1\over p_i}) ϕ(x)=n(1pi1)
实际代码的时候需要我们把上述括号通分了再计算. ( p i − 1 ) p (pi-1) \over p p(pi1),那么对于单个数字x的 ϕ ( x ) , 找 到 一 个 x % p = = 0 的 数 字 p , 直 接 让 n 包 含 p 的 因 子 全 部 去 除 , 这 样 我 们 保 证 了 , 每 次 找 到 一 个 p , 必 然 是 唯 一 分 解 中 对 应 的 p . 因 为 我 们 每 次 找 到 一 个 p , 是 把 它 对 应 的 贡 献 全 部 去 掉 , 那 么 这 个 p 必 然 是 我 们 要 找 到 的 唯 一 分 解 的 p \phi(x),找到一个x\%p==0的数字p,直接让n包含p的因子全部去除,这样我们保证了,每次找到一个p,必然是唯一分解中对应的p.因为我们每次找到一个p,是把它对应的贡献全部去掉,那么这个p必然是我们要找到的唯一分解的p ϕ(x),x%p==0p,np,,pp.p,,pp.
单个欧拉函数的计算,类似于试除法.
注意,我们是在枚举 n \sqrt{n} n 范围内的素数,并没有讨论 n n n本身是素数的情况,那种情况我们放在函数末尾处理,即 x > 1 x>1 x>1的情况.
单个 ϕ ( x ) 的 计 算 情 况 \phi(x)的计算情况 ϕ(x)

int phi(int x){
	int ans = n;//phi(x) = n / {(1-1/p1)*(1-1/p2)...} 
	for(int i=2;i<=(int)(sqrt(x+0.5));i++){
		if(x%i==0){
			ans = ans / i * (i-1);
		}
		while(x%i==0) x/=i;  
	}
	//如果x还不是1,说明x当前就是一个素数.而我们枚举的素数的范围
	//是[1,根号x].没有枚举自己.
	if(x>1) ans = ans/n*(n-1); 
}

与素数筛法类似,我们也能以几乎线性的时间求出欧拉函数.
先给代码再解释原理:

void phi_table(int n){
	for(int i=2;i<=n;i++) phi[i]=0;
	phi[1]=1;
	for(int i=2;i<=n;i++) {
		if(!phi[i]){
			for(int j=i;j<=n;j+=i){
				if(!phi[j]) phi[j] = j;
				phi[j] = phi[j] / i *(i-1);
			}
		}
	}
}

原理:模仿素数筛,我们想每次枚举出一个素数 i i i,然后把包含该素数的所有数字对应的贡献都计算完毕,这样时间复杂度就能优化.
我们枚举该素数 i i i的倍数 j j j,若当前 p h i [ j ] phi[j] phi[j]没有赋值,就让 p h i [ j ] = j phi[j]=j phi[j]=j.这相当于单个 p h i phi phi函数中的在这里插入图片描述
然后我们知道,对于每一个枚举出来的,含有 i i i因子的数字,都要统计该素数 i i i的贡献.
故有 p h i [ j ] = p h i [ j ] / i ∗ ( i − 1 ) phi[j]=phi[j]/i*(i-1) phi[j]=phi[j]/i(i1)与单个 p h i phi phi函数一致.
最后,代码外层循环在这里插入图片描述
保证每个素数 i i i不会被重复计算贡献.
该笔记完,接下来施工练习题.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值