欧拉函数求法总结及相关例题

本文深入探讨了欧拉函数的计算方法,包括单个数的欧拉函数值求解和一段数的欧拉函数值求解。介绍了两种求解一段数欧拉函数值的方法:埃拉托斯特尼筛法和欧拉筛法,并详细解释了欧拉筛法的原理和证明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:本博客并非写给欧拉函数的初学者,而是为已经学会欧拉函数的OIer们提供一点总结。


题型一:求解单个数的欧拉函数值

模板题:POJ2407

方法:根据公式求解

根据欧拉函数的通项公式 φ ( x ) = x ∏ i = 1 n ( 1 − 1 p i ) \varphi(x)=x\prod_{i=1}^{n}(1-\frac{1}{p_{i}}) φ(x)=xi=1n(1pi1)通过对数x进行类似质因数分解的操作完成单个欧拉函数值的计算。复杂度 Θ ( x ) \Theta(\sqrt{x}) Θ(x )
代码:

#include<cstdio>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
int n;
int main(){
	while(scanf("%d",&n)==1&&n!=0){
		int ans=n,lim=sqrt(n);
		rep(i,2,lim) if(n%i==0){
			ans=ans/i*(i-1);//先除再乘,避免爆int
			while(n%i==0) n/=i; 
		}
		if(n>1) ans=ans/n*(n-1);
		printf("%d\n",ans);
	}
	return 0;
}
题型二:求解一段数的欧拉函数值

模板题:HDU2824

方法一:利用埃拉托斯特尼筛求解一段数的欧拉函数值

当需要求解一段连续的几十万个数的欧拉函数时,使用第一种方法基本上就TLE了,我们利用埃氏筛在用素数p筛除其他数的同时,计算p对每一个被筛的数欧拉函数的贡献,复杂度是 Θ ( n l o g l o g n ) \Theta(nloglogn) Θ(nloglogn)。具体见代码。

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
const int inf=1e9+10,N=3e6+100;
int a,b,phi[N+1];
bool prime[N+1];//false为素数,true为合数。 
long long ans;
inline void Eratos_to_Euler(){
	rep(i,2,N) phi[i]=i;
	rep(i,2,N)
		if(prime[i]==false)
			for(int j=i;j<=N;j+=i)
				phi[j]=phi[j]/i*(i-1),prime[j]=true;
}
int main(){
	Eratos_to_Euler();
	while(scanf("%d%d",&a,&b)==2){
		long long ans=0;
		rep(i,a,b) ans+=phi[i];
		printf("%lld\n",ans);
	}
	return 0;
}

方法二:利用欧拉筛求解一段数的欧拉函数值

同样也是在筛除其他数的同时算出被筛数的欧拉函数,但并不是像埃氏筛那样子使用每一个素数计算对被筛数的贡献——那样复杂度是 Θ ( n l o g l o g n ) \Theta(nloglogn) Θ(nloglogn)的。而是通过欧拉函数的性质(也可以理解是通项)来推出被筛数的欧拉函数。具体如下:
在欧拉筛中,当 p j p_{j} pj整除 i i i时, φ ( p j ∗ i ) = φ ( i ) ∗ p j \varphi(p_{j}*i)=\varphi(i)*p_{j} φ(pji)=φ(i)pj
否则 φ ( p j ∗ i ) = φ ( i ) ∗ ( p j − 1 ) \varphi(p_{j}*i)=\varphi(i)*(p_{j}-1) φ(pji)=φ(i)(pj1)
证明:
以下是一种我认为相当直观好理解的证明方法(自己想到的):
1.当 p j p_{j} pj整除 i i i时,也就是 i i i含有 p j p_{j} pj这个素因子,那么被筛数 a = i ∗ p j a=i*p_{j} a=ipj的不同的素因子个数完全没有改变,在欧拉函数的通项公式中:
φ ( x ) = x ∏ i = 1 n ( 1 − 1 p i ) \varphi(x)=x\prod_{i=1}^{n}(1-\frac{1}{p_{i}}) φ(x)=xi=1n(1pi1)
我们可以知道 a a a i i i ∏ i = 1 n ( 1 − 1 p i ) \prod_{i=1}^{n}(1-\frac{1}{p_{i}}) i=1n(1pi1)这一部分是一模一样的。因此 φ ( a ) \varphi(a) φ(a)的值与 φ ( i ) \varphi(i) φ(i)的值区别只在于 x x x,而 a = i ∗ p j a=i*p_{j} a=ipj,所以差的是一个x中的 p j p_{j} pj,因此当 p j p_{j} pj整除 i i i时, φ ( p j ∗ i ) = φ ( i ) ∗ p j \varphi(p_{j}*i)=\varphi(i)*p_{j} φ(pji)=φ(i)pj

2.根据同样的思路,当 p j p_{j} pj不整除 i i i时,也就是 i i i不含有 p j p_{j} pj这个素因子。
那么被筛数 a = i ∗ p j a=i*p_{j} a=ipj的不同的素因子个数只改变增加了一个,那就是 p j p_{j} pj.
因此在 φ ( a ) = φ ( i ) ∗ p j \varphi(a)=\varphi(i)*p_{j} φ(a)=φ(i)pj的基础上,还要再乘上一个值,那就是 p j − 1 p j \frac{p_{j}-1}{p_{j}} pjpj1.
φ ( a ) = φ ( i ) ∗ p j ∗ p j − 1 p j = φ ( i ) ∗ ( p j − 1 ) \varphi(a)=\varphi(i)*p_{j}*\frac{p_{j}-1}{p_{j}}=\varphi(i)*(p_{j}-1) φ(a)=φ(i)pjpjpj1=φ(i)(pj1)。证毕。

复杂度 Θ ( n ) \Theta(n) Θ(n)
模板题同上:

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
using namespace std;
typedef long long ll;
const int inf=1e9+10,N=3e6+100;
int a,b,phi[N+1],v[N],prime[N],len;
inline void Euler_to_Euler(){
	rep(i,2,N){
		if(v[i]==0){
			v[i]=i;
			phi[i]=i-1;
			prime[++len]=i;
		}
		rep(j,1,len){
			if(prime[j]>N/i||prime[j]>v[i]) break;
			//最好写成 prime[j]>N/i,而不是i*prime[j]>N,避免爆int。
			v[i*prime[j]]=prime[j];//筛 
			if(i%prime[j]==0) phi[i*prime[j]]=phi[i]*prime[j];//计算欧拉函数 
				else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
}
int main(){
	Euler_to_Euler();
	while(scanf("%d%d",&a,&b)==2){
		long long ans=0;
		rep(i,a,b) ans+=phi[i];
		printf("%lld\n",ans);
	}
	return 0;
}

觉得写得好的话,就点个赞让我知道一下呗~

<think>好的,用户需要关于微分方程的例题和教程,特别是示例题目和解法。首先,我需要根据他们提供的引用内容来整理相关信息。用户提到的引用[1]和[2]涉及常微分方程的数值解法,比如欧拉法和Matlab中的dsolve函数。因此,我应该结合这些方法给出具体的例子。 首先,我应该区分解析解和数值解法。用户可能需要两种类型的例题,所以分别准备。例如,对于解析解,可以选一个一阶线性微分方程,使用分离变量法或积分因子法来解,并用Matlab的dsolve函数展示代码。对于数值解法,引用[1]提到了欧拉法,所以可以举一个欧拉法的例子,给出具体的步骤和Matlab实现。 接下来,要确保例题的难度适中,适合教学。比如,选择dy/dx = x + y作为例子,因为它结构简单,适合演示欧拉法的迭代过程。同时,选择dy/dx = y这样的方程,因为它的解析解容易验证,适合展示符号解法。 在编写数值解法的步骤时,需要详细说明欧拉法的公式,即yn+1 = yn + h*f(xn, yn),并给出具体的参数,如步长h=0.1,迭代次数等。同时,要对比解析解和数值解的结果,显示误差,这样用户能理解方法的精度。 对于Matlab代码部分,要确保语法正确,使用正确的函数,比如ode45和欧拉法的自定义函数。引用[2]提到了dsolve的使用,所以在解析解的例子中需要包含这个函数,并正确应用初值条件。 另外,用户可能需要更多资源推荐,所以准备一些经典的教材和在线资源,比如《常微分方程教程》和MIT的公开课,这些资源可以帮助用户深入学习。 最后,生成相关时要覆盖解析解与数值解的区别、欧拉法的改进、选择数值方法的依据等,这样用户可以通过这些问进一步探索微分方程的不同方面。 检查所有数学公式是否正确使用$$...$$和$...$格式,确保没有语法错误。例如,微分方程写成$$ \frac{dy}{dx} = x + y $$,而欧拉法的公式用$$ y_{n+1} = y_n + h \cdot f(x_n, y_n) $$。同时,引用文献的标识要正确添加,比如在欧拉法介绍后加上[^1],在Matlab代码示例后引用[^2]。 总结来说,我需要提供两个例题,分别展示解析解和数值解法,给出详细的步骤和代码,并附上相关和资源推荐,确保结构清晰,符合用户的要求。</think>### 微分方程例题及解法 #### 例题1:一阶线性微分方程(解析解) **目** 求微分方程 $$ \frac{dy}{dx} = y $$ 满足初始条件 $y(0)=2$ 的解。 **解法** 1. **分离变量法** 方程改写为: $$ \frac{dy}{y} = dx $$ 两边积分得: $$ \ln|y| = x + C $$ 代入初始条件 $y(0)=2$,得 $C=\ln2$,因此解为: $$ y = 2e^{x} $$ 2. **Matlab符号解法** ```matlab syms y(x) eqn = diff(y,x) == y; cond = y(0) == 2; sol = dsolve(eqn, cond); disp(sol); % 输出: 2*exp(x) ``` 使用 `dsolve` 函数可直接求解。 --- #### 例题2:一阶微分方程数值解(欧拉法) **目** 用欧拉法近似求解 $$ \frac{dy}{dx} = x + y $$,初始条件 $y(0)=1$,步长 $h=0.1$,计算区间 $[0,0.3]$。 **解法** 1. **欧拉法公式** $$ y_{n+1} = y_n + h \cdot f(x_n, y_n) $$ 其中 $f(x,y)=x+y$。 2. **迭代计算** - **第1步** ($x_0=0$): $y_1 = 1 + 0.1 \cdot (0 + 1) = 1.1$ - **第2步** ($x_1=0.1$): $y_2 = 1.1 + 0.1 \cdot (0.1 + 1.1) = 1.22$ - **第3步** ($x_2=0.2$): $y_3 = 1.22 + 0.1 \cdot (0.2 + 1.22) = 1.362$ 3. **Matlab实现** ```matlab function y_euler = euler_method(f, y0, h, x_end) x = 0:h:x_end; y_euler = zeros(size(x)); y_euler(1) = y0; for n = 1:length(x)-1 y_euler(n+1) = y_euler(n) + h * f(x(n), y_euler(n)); end end % 调用示例 f = @(x,y) x + y; y0 = 1; h = 0.1; x_end = 0.3; y = euler_method(f, y0, h, x_end); disp(y); % 输出: [1, 1.1, 1.22, 1.362] ``` 此方法为显式欧拉法,适用于简单方程的初步近似。 --- #### 拓展资源推荐 1. **教材** - 《常微分方程教程》(丁同仁) - 《Differential Equations and Their Applications》(F. Brauer) 2. **在线课程** - MIT OpenCourseWare: 微分方程导论 - Coursera: 实用科学计算(含微分方程数值解) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值