[浅谈] 欧拉函数

definition

φ(n) 表示不超过 n 且与 n 互质的正整数的个数。
欧拉函数是一个数论函数(定义域为正整数)和积性函数(对于互质的正整数 a,b 满足 f(a,b)=f(a)f(b)

积性函数的性质:
n=piai(pi)
f(n)=f(piai)

theorem

  1. φ(p)=p1(p)
  2. φ(pa)=papa1=(p1)pa1(p)
    因为 pxpa 不互质,总共有 pa1 个这样的数,剩下的数就是与它互质的数。
  3. 2 推得: φ(n)=φ(pisi)φ(n)=(pi1)pisi1=n(11pi)
  4. 由积性函数:φ(2n)=φ(n)(n)
  5. n=d|nφ(d)
  6. φ(n)(n>2)
  7. 欧拉定理: 对于互质正整数 a,mm2aφ(m)1(modm)
  8. 费马小定理: 对于质数 ma 不为 m 的倍数, am11(modm)
  9. 拓展欧拉定理:
    (a,m)=1,ababmodφ(m)(modm)
    bφ(m),aba(bmodφ(m))+φ(m)(modm)
    例题:
    P4139 上帝与集合的正确用法
    CF906D Power Tower

定义求欧拉函数

点击查看代码
int phi(int x){
	int p=1;
	for(int i=2;i*i<=x;i++){
		if(x%i)continue;
		p*=i-1;x/=i;
		while(x%i==0)p*=i,x/=i;
	}
	if(x>1)p*=x-1;
	return p;
}

筛法求欧拉函数

点击查看代码
phi[1]=1;bk[1]=1;
for(int i=2;i<=maxn;i++){
	if(!bk[i]){
		prime[++tot]=i;
		phi[i]=i-1;
	}
	for(int j=1;j<=tot;j++){
		if(i*prime[j]>maxn)break;
		bk[i*prime[j]]=1;
		phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
		if(i%prime[j]==0)break;
	}
}

CF906D Power Tower

拓欧的应用不过是给指数运算取模罢了。

wl+1wl+2...φ(P)wlwl+1...modP=wlwl+1wl+2modφ(P)+φ(P)modP

wl+1wl+2...<φ(P)wlwl+1...modP=wlwl+1wl+2modφ(P)modP

递归终点显然是 P=1l=r 。因为 P 下降的很快,大概是 log 级别,所以直接递归即可,不用优化。

那么剩下的问题就在分类上了:我们不知道 wl+1wl+2...,φ(P) 之间的大小关系。
一种可行的方法是对取模做手脚,取模时对于 x>P 时,变为 xmodP+P 。 这样倘若大于,就自动加上了 φ(P)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=1e5+110;
int read(){
	int x=0,f=1;char c=getchar();
	while(c>'9' || c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
map<int,int>mp;
int n,P,q,a[M];
int nmo(int x,int p){
	return x<p?x:(x%p+p);
}
int ksm(int x,int y,int pp){
	int sum=1;
	while(y){
		if(y&1)sum=nmo(sum*x,pp);
		x=nmo(x*x,pp);y>>=1;
	}
	return sum;
}
int getphi(int x){
	int ans=1;
	for(int i=2;i*i<=x;i++){
		if(x%i)continue;
		ans*=i-1;x/=i;
		while(x%i==0)
			ans*=i,x/=i;
	}
	if(x>1)ans*=x-1;
	return ans;
}
int solve(int i,int r,int p){
	if(i==r || p==1)return nmo(a[r],p);
	int yp=(mp[p]?mp[p]:(mp[p]=getphi(p)));
	return ksm(a[i],solve(i+1,r,yp),p);
}
signed main(){
	n=read();P=read();
	for(int i=1;i<=n;i++)a[i]=read();
	q=read();
	for(int i=1;i<=q;i++){
		int l=read(),r=read();
		printf("%lld\n",solve(l,r,P)%P);
	}
	return 0;
}
posted @   FJOI  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示