欧拉函数

前言

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

φ ( 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 ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) ⋅ ⋅ ⋅ ⋅ ( 1 − 1 p n ) \varphi (x)=x(1-\frac{1}{p_1})(1-\frac{1}{p_{2}})\cdot \cdot \cdot \cdot (1-\frac{1}{p_{n}}) φ(x)=x(1p11)(1p21)(1pn1)

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

  1. 若n是质数p的k次幂,则 φ ( x ) = p k − p k − 1 = ( p − 1 ) p k − 1 \varphi (x)=p^{k}-p^{k-1}=(p-1)p^{k-1} φ(x)=pkpk1=(p1)pk1
    因为除了p的倍数外,其他数都跟n互质。
  2. 欧拉函数是非完全积性函数:若m,n互质,则 φ ( m ∗ n ) = φ ( m ) ∗ φ ( n ) \varphi (m*n)=\varphi (m)*\varphi (n) φ(mn)=φ(m)φ(n)
  3. 当n为奇质数时, φ ( 2 n ) = φ ( n ) \varphi (2n)=\varphi (n) φ(2n)=φ(n)
  4. 若n为质数,则 φ ( n ) = n − 1 \varphi (n)=n-1 φ(n)=n1
  5. 若a为素数,b mod a=0,则 φ ( a ∗ b ) = a ∗ φ ( b ) \varphi (a*b)=a*\varphi (b) φ(ab)=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=dnφ(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 ⋅ p n − x = k ⋅ q \left\{\begin{matrix} n=k\cdot p\\ n-x=k\cdot q \end{matrix}\right. {n=kpnx=kq,那么x=k * p-k * q=k * (p-q),那么n,x都有k这个约数,与假设冲突。
同时不难发现,若小a在某个位置获得了 k x k^{x} kx的贡献,那么一定存在一个位置会获得 k n − x k^{n-x} knx的贡献,而且两个人的贡献是相同的!
把小a的贡献单独写出来即为 A ∗ k a ∗ k n − a ∗ k b ∗ k n − b ⋅ ⋅ ⋅ ⋅ = A ∗ k R n A\ast k^{a}\ast k^{n-a}\ast k^{b}\ast k^{n-b}\cdot \cdot \cdot \cdot =A \ast k^{Rn} Akaknakbknb=AkRn
考虑如何快速得到R的值,观察题目描述不难发现,能产生答案的数一定是与n互质的数,这与ϕ函数的定义是相同的!
又因为前n个数的欧拉函数之和为 n φ ( n ) 2 \frac{n\varphi (n)}{2} 2nφ(n)

因此最终的答案为 ( A + B ) ∗ K n φ ( 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;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值