您的位置:首页 > 其它

欧拉函数

2019-06-20 07:21 2221 查看
版权声明:本文为博主原创文章,转载需注明出处。 https://blog.csdn.net/qq_43454912/article/details/90677146

前言

欧拉函数φ(n)是小于n的正整数中与n互质的数的数目(φ(1)=1),
φ(n)称为n的欧拉值
例如φ(8)=4(2,3,5,7)。
公式如下

φ(x)=x∏i=1n(1−1pi)\varphi (x)=x\prod_{i=1}^{n}(1-\frac{1}{p_i})φ(x)=x∏i=1n​(1−pi​1​)

也就是φ(x)=x(1−1p1)(1−1p2)⋅⋅⋅⋅(1−1pn)\varphi (x)=x(1-\frac{1}{p_1})(1-\frac{1}{p_{2}})\cdot \cdot \cdot \cdot (1-\frac{1}{p_{n}})φ(x)=x(1−p1​1​)(1−p2​1​)⋅⋅⋅⋅(1−pn​1​)

其中pi为x的所有质因数,x不为零。
注意:每种质因数只一个。
欧拉函数有如下性质:

  1. 若n是质数p的k次幂,则φ(x)=pk−pk−1=(p−1)pk−1\varphi (x)=p^{k}-p^{k-1}=(p-1)p^{k-1}φ(x)=pk−pk−1=(p−1)pk−1
    因为除了p的倍数外,其他数都跟n互质。
  2. 欧拉函数是非完全积性函数:若m,n互质,则φ(m∗n)=φ(m)∗φ(n)\varphi (m*n)=\varphi (m)*\varphi (n)φ(m∗n)=φ(m)∗φ(n)
  3. 当n为奇质数时,φ(2n)=φ(n)\varphi (2n)=\varphi (n)φ(2n)=φ(n)
  4. 若n为质数,则φ(n)=n−1\varphi (n)=n-1φ(n)=n−1
  5. 若a为素数,b mod a=0,则φ(a∗b)=a∗φ(b)\varphi (a*b)=a*\varphi (b)φ(a∗b)=a∗φ(b)
  6. 当n>2时,φ(n)是偶数。
  7. 小于n的数中,与n互质的数的总和为:nφ(n)2\frac{n\varphi (n)}{2}2nφ(n)​ (n>1)。
  8. n=∑d∣nφ(d)n=\sum_{d\mid n}φ(d)n=∑d∣n​φ(d),即n的因数(包括1和它自己)的欧拉函数之和等于n

实现

如何求1到n区间内所有数的欧拉值,下面代码是基于线性素数筛法(传送门)

#include<stdio.h>
#include<string.h>
int prime[10000],ans=0;//存放素数的数组
bool sign[10000];//标记,0为素数,1不为素数
int euler[10000];//欧拉值数组,初始化为1
void Euler(int n){
memset(sign,0,sizeof(sign));
euler[1]=1;//φ(1)=1
for(int i=2;i<=n;i++){
if(!sign[i]){//判断是否标记,未标记的为素数
prime[ans++]=i;//保存素数i
euler[i]=i-1;//性质四
}
for(int j=0;j<ans&&i*prime[j]<=n;j++) {
sign[prime[j]*i]=1;//i*prime[j]不为素数,标记它
if(i%prime[j]==0){//看p[j]是否是i的约数,因为p[j]为素数,等于判断i和p[j]是否互质
euler[prime[j]*i]=euler[i]*prime[j];//性质五
break;
}else{
euler[prime[j]*i]=euler[i]*(prime[j]-1); //性质二
}
}
}
}
void show(int n){
for(int i=1;i<=n;i++){
printf("%d ",euler[i]);
}
}
int main(){
int n;
scanf("%d",&n);
Euler(n);
show(n);
return 0;
}

练习

看完上面的解析,想必已经跃跃欲试了,现在上题
首先发出题目链接:
链接:https://ac.nowcoder.com/acm/contest/317/D
来源:牛客网
涉及:欧拉函数
看完题目,首先不难发现,若gcd(n, x) = 1,那么gcd(n, n − x)一定等于1
证明:反证法,gcd(n,x)=gcd(n,n-x)=k
若{n=k⋅pn−x=k⋅q\left\{\begin{matrix} n=k\cdot p\\ n-x=k\cdot q \end{matrix}\right.{n=k⋅pn−x=k⋅q​,那么x=k * p-k * q=k * (p-q),那么n,x都有k这个约数,与假设冲突。
同时不难发现,若小a在某个位置获得了kxk^{x}kx的贡献,那么一定存在一个位置会获得kn−xk^{n-x}kn−x的贡献,而且两个人的贡献是相同的!
把小a的贡献单独写出来即为A∗ka∗kn−a∗kb∗kn−b⋅⋅⋅⋅=A∗kRnA\ast k^{a}\ast k^{n-a}\ast k^{b}\ast k^{n-b}\cdot \cdot \cdot \cdot =A \ast k^{Rn}A∗ka∗kn−a∗kb∗kn−b⋅⋅⋅⋅=A∗kRn,
考虑如何快速得到R的值,观察题目描述不难发现,能产生答案的数一定是与n互质的数,这与ϕ函数的定义是相同的!
又因为前n个数的欧拉函数之和为nφ(n)2\frac{n\varphi (n)}{2}2nφ(n)​。

因此最终的答案为(A+B)∗Knφ(n)2(A+B) \ast K^{\frac{n\varphi (n)}{2}}(A+B)∗K2nφ(n)​
AC代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll oula(ll n){//欧拉函数求互质数的个数
ll i,ans=n;
for(i=2;i*i<=n;i++){
if(n%i==0){
ans=ans-ans/i;
do{
n/=i;
}while(n%i==0);
}
}
if(n>1){
ans=ans-ans/n;
}
return ans;
}
ll pl(ll sum,ll p){
ll ans=1;
while(p){
if(p&1){
ans=ans*sum%1000000007;
}
sum=sum*sum%1000000007;
p>>=1;
}
return ans;
}
int main(){
ll n,k,a,b,p,ans;
cin >> n >> k >> a >> b;
p=oula(n);
ll sum=0;
p=p/2*(n);
sum=a+b;
ans=pl(k,p);
cout << ans*sum%1000000007;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: