欧拉函数入门

前置芝士——线性筛质数

思路

考虑问题 1~x中有多少个质数(1<x<=1e7)

1、首先考虑将质数的倍数都标记为合数(即埃筛),时间复杂度 O(n log^2 n ) , n上限大约在百万左右。

2、考虑时间复杂度优化:

        发现对于合数 6 ,被 质因数 2,3 都筛了一次,造成时间浪费。

        所以指定对于每一个合数只被其最小质因数筛掉。

3、实现:对每个数i,如果i是质数则将它加进质数表;把当前数i(不管是质数还是合数)与目前质数表中每个不超过自己最小质因子的质数的乘积变为合数。

        原因:i 的最小质因子以后会与更大的合数相乘,枚举质数表中的质数超过i的最小质因子没有必要.

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int x;
int prime[N],tot;//已求得质数表
bool isprime[N];//isprime[i]表示 i 是否为质数
int main(){
	cin>>x;
	for(int i=2;i<=x;i++){
		if(!isprime[i]) {//是质数
			prime[++tot]=i;
		}
		for(int j=1;j<=tot&&i*prime[j]<=x;j++) {
			isprime[i*prime[j]]=1;//标记合数
			if(i%prime[j]==0) break;//重要优化
		}
	}
	//由于每个数至多被筛一次 ,时间复杂度 O(n)
	return 0;
}

欧拉函数

定义

\varphi (n) 表示 小于等于 n 与 n 互质的数的个数

特别规定 \varphi (1)=1

欧拉函数计算式

对于 \varphi (n),考虑计算1~n中不与 n 互质的个数,即 n 质因数倍数

举个栗子,12=2^2*3,2的倍数有 2、4、6、8、10、12;3的倍数有3、6、9、12

发现 6 和 12 重复减了,加上。

自然想到容斥原理

由此易得代码实现

int getphi(int x){
	int ans=x;
	for(int i=2;i*i<x;i++){
		if(x%i==0 ){
			ans=ans*(i-1)/i;
			while(x%i==0) x/=i;
		}
	}
	if(x>1) ans=ans*(x-1)/x;
	return ans;
}

欧拉函数性质

一、欧拉函数是积性函数

积性函数:函数 f(x), 对于互质的数 a,b ,满足f(ab)=f(a)*f(b)

证明 :因为 a,b 互质,所以两者没有相同质因数。由欧拉函数计算式易证。

二、简单性质

(1)若n是质数,φ(n) = n - 1。

(2)若n=p^k 且p是质数, 则\varphi(n)=(p-1)p^{k-1}

(3)若q是质数,且n % q = 0,则\varphi(nq)= q\varphi(n) ;  

       若q是质数,且n % q ≠ 0,则\varphi(nq) = (q-1)\varphi(n)

上述结论均可由计算式简单推倒得到,在此不多赘述。

三、重要结论

1、n=\sum _{n|d} \varphi(d)

证明先咕着<-^_^->

2、\varphi(a*b)=\varphi(a)*\varphi(b)*\frac{d}{\varphi(d)}     d=gcd(a,b)

证明:a 的质因数集合为 A,b 的质因数集合为 B,d 的质因数集合 C 为 A\bigcap B

带入欧拉函数计算式得证

四、其他结论

1、设d(n)表示n的约数的个数,则d(n)是积性函数

证明:令 n = AB,且AB互质。设A=p_1^{x1}p_2^{x2}...p_n^{xn}    B=q_1^{y1}q_2^{y2}...q_n^{ym}   

d(A) = (x1+1)(x2+1)...(xn+1),    d(B) = (y1+1)(y2+1)...(ym+1)。

因为AB互质,所以所有的p和q肯定都是不同的质因子。

d(A)*d(B) = (x1+1)(x2+1)...(xn+1)(y1+1)(y2+1)...(ym+1) = d(n)。

2、设s(n)表示n的所有约数的和,则s(n)是积性函数

证明:令 n = AB,且AB互质。设A=p_1^{x1}p_2^{x2}...p_n^{xn}    B=q_1^{y1}q_2^{y2}...q_n^{ym}   

重要特性

积性函数均可由线性筛求值

线性筛求欧拉函数

通过上述性质由线性筛得到

void work(int x){
	phi[1]=1;
	for(int i=2;i<=x;i++){
		if(!isprime[i]) {
			prime[++tot]=i;
			phi[i]=i-1;//由性质1
		}
		for(int j=1;j<=tot&&prime[j]*i<=x;j++) {
			int fx=prime[j]*i;
			isprime[fx]=1;
			if(i%prime[j]==0) {
				phi[fx]=phi[i]*prime[j];//性质3
				break;
			}
			phi[fx]=phi[i]*(prime[j]-1);//性质3
		}
	}
}

下期预告:欧拉函数常见题型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值