欧拉函数算法的实现

124

57
欧拉函数
对于正整数nn,欧拉函数是小于或等于nn的正整数中与nn互质的数的数目,记作φ(n)φ(n).
φ(1)=1φ(1)=1
求n的欧拉值
首先, 欧拉函数是一个积性函数,当m,nm,n互质时,φ(mn)=φ(m)∗φ(n)φ(mn)=φ(m)∗φ(n)
根据唯一分解定理知 n=pa11∗pa22∗…∗paxxn=p1a1∗p2a2∗…∗pxax
因此 φ(n)=φ(pa11)∗…∗φ(paxx)φ(n)=φ(p1a1)∗…∗φ(pxax)
对于任意一项 φ(pass)=pass−p(as−1)sφ(psas)=psas−ps(as−1)
从定义出发 φ(pass)φ(psas)等于小于或等于passpsas的正整数中与passpsas互质的数的数目

从11到passpsas中共有passpsas个数字

其中与passpsas不互质的有ps,2ps,…,psas−1∗psps,2ps,…,psas−1∗ps ,共psas−1psas−1项

所以 φ(pass)φ(psas) = passpsas - psas−1=pass∗(1−1ps)psas−1=psas∗(1−1ps)
因此

φ(n)=φ(pa11)∗…∗φ(paxx)
φ(n)=φ(p1a1)∗…∗φ(pxax)
=(pa11−p1a1−1)∗…∗(paxx−pxax−1)
=(p1a1−p1a1−1)∗…∗(pxax−pxax−1)
=pa11∗(1−1p1)∗pa22∗(1−1p2)∗…∗paxx∗(1−1px)
=p1a1∗(1−1p1)∗p2a2∗(1−1p2)∗…∗pxax∗(1−1px)
=pa11∗pa22∗…∗paxx∗(1−1p1)∗(1−1p2)∗…∗(1−1px)
=p1a1∗p2a2∗…∗pxax∗(1−1p1)∗(1−1p2)∗…∗(1−1px)
=n∗∏i=1x(1−1pi)

给定n个正整数ai,请你求出每个数的欧拉函数。

欧拉函数的定义
1 ~ N 中与 N 互质的数的个数被称为欧拉函数,记为ϕ(N)。
若在算数基本定理中,N=pa11pa22…pamm,则:
ϕ(N) = N∗p1−1p1∗p2−1p2∗…∗pm−1pm
输入格式
第一行包含整数n。

接下来n行,每行包含一个正整数ai。

输出格式
输出共n行,每行输出一个正整数ai的欧拉函数。

数据范围
1≤n≤100,
1≤ai≤2∗109
输入样例:

3
3
6
8
输出样例:

2
2
4

字不太好,见笑了
证明方法一(含积性函数证明)

证明方法二

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll k;cin>>k;
while(k–)
{
ll x;
cin>>x;
ll res=x;
for(ll i=2;i<=x/i;i++)
if(x%i0)
{
while(x%i
0)x/=i;
res=res/i*(i-1); //注意先除再乘 N/pk*(pk-1);
}
if(x>1)res=res/x*(x-1);
cout<<res<<endl;
}
题目描述
给定 nn 个正整数 aiai,请你求出每个数的欧拉函数。

欧拉函数的定义
1∼N1∼N 中与 NN 互质的数的个数被称为欧拉函数,记为 ϕ(N)ϕ(N)。
若在算数基本定理中,N=pa11pa22…pammN=p1a1p2a2…pmam,则:
ϕ(N)=N×p1−1p1×p2−1p2×…×pm−1pmϕ(N)=N×p1−1p1×p2−1p2×…×pm−1pm
输入格式
第一行包含整数 nn。

接下来 nn 行,每行包含一个正整数 aiai。

输出格式
输出共 nn 行,每行输出一个正整数 aiai 的欧拉函数。

数据范围
1≤n≤1001≤n≤100,
1≤ai≤2×1091≤ai≤2×109
输入样例:
3
3
6
8
输出样例:
2
2
4
算法1
(欧拉函数) O(n2)O(n2)
这道题叫我们求的是欧拉函数
不知道大家看懂了没有,其实看上去很恐怖,但是重要的也就这一句,其实挺好懂的
1∼N1∼N 中与 NN 互质的数的个数被称为欧拉函数,记为 ϕ(N)ϕ(N)。

那知道了欧拉函数是什么东西,那我们怎么证明欧拉函数呢?

证明如图:

时间复杂度
参考文献
C++ 代码
#include
using namespace std;
int main(){
int n; //需要判断的数的个数
scanf(“%d”,&n);
while(n --){ //n个数
int a;
long long res; //记得这里要long long哦,数据加强了QWQ,坑死人
scanf(“%d”,&a);
res = a; //把res赋值为这个数
for(int i = 2;i <= a / i;i ++){ //找质因数
if(a % i == 0){ //如果这个数是可以整除a的
res = res * (i - 1) / i;
//这个式子是转换过来的
//原式为:
//res * (1 - 1 / i)
//因为1 / i有可能为小数,而/是整除的意思,和答案可能不符
//所以我们在后面*i再/i就可以化简成这样啦
//详细化简过程见解析①
while(a % i == 0) a /= i; //把a除到a的最小质因数
}
}
if(a > 1) res = res * (a - 1) / a; //如果还大于1,说明还有一个质因子为a
printf(“%lld\n”,res); //输出答案
}
return 0;
}
如果分解质因子的地方看不懂,可以先看一下我的题解约数个数或约数之和

解析①:
化简过程:
res×(1−1i)
res×(1−1i)

=res×(1−1i)×i÷i
=res×(1−1i)×i÷i

=res×(i−1)÷i
=res×(i−1)÷i
化简完成,当然也可以写成这种形式:
(res×i−res)÷i
(res×i−res)÷i
这种形式的代码:

#include
using namespace std;
int main(){
int n;
scanf(“%d”,&n);
while(n --){
int a;
long long res;
scanf(“%d”,&a);
res = a;
for(int i = 2;i <= a / i;i ++){
if(a % i == 0){
res = (res * i - res) / i;
while(a % i == 0) a /= i;
}
}
if(a > 1) res = (res * a - res) / a;
printf(“%lld\n”,res);
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值