拓展欧拉定理+幂塔函数

拓展欧拉定理与幂塔函数

欧拉定理: 若gcd(a,p) = 1,则 a p ≡ a b % φ ( p ) ( m o d   p ) a^p \equiv a^{b \% \varphi (p)}(mod \: p) apab%φ(p)(modp),其中gcd(a,p) = 1。
拓展欧拉定理: 假设a为任意数,b和m为正整数,且 b > φ ( m ) b > \varphi(m) b>φ(m),a和m不一定要互质,那么有如下公式:
a b   ≡   { a b   M o d   ϕ ( m ) gcd ⁡ ( a , m )   =   1 a b gcd ⁡ ( a , m )   ≠   1   ∧   b   &lt;   ϕ ( m ) a b   M o d   ϕ ( m )   +   ϕ ( m ) gcd ⁡ ( a , m )   ≠   1   ∧   b   ≥   ϕ ( m ) &MediumSpace;&MediumSpace; ( M o d &MediumSpace; m ) a^b~\equiv~\begin{cases}a^{b~Mod~\phi(m)} &amp;\gcd(a,m)~=~1 \\a^b &amp;\gcd(a,m)~\neq~1~\land~b~&lt;~\phi(m) \\ a^{b~Mod~\phi(m)~+~\phi(m)} &amp;\gcd(a,m)~\neq~1~\land~b~\geq~\phi(m)\end{cases} \:\:(Mod\: m) ab  ab Mod ϕ(m)abab Mod ϕ(m) + ϕ(m)gcd(a,m) = 1gcd(a,m) ̸= 1  b < ϕ(m)gcd(a,m) ̸= 1  b  ϕ(m)(Modm)

注:拓展欧拉定理的证明可以参考证明

幂塔函数: 形如
a a a . . . m o d &MediumSpace; m a^{a^{a^{...}}} mod \: m aaa...modm
的函数我们称为幂塔函数,该函数应从上向下计算,即 a a a a = a ( a ( a a ) ) a^{a^{a^a}} = a^{(a^{({a^a})})} aaaa=a(a(aa)),因此其中间变量会急剧上升,普通方法无法计算。

例题:2019南京icpc网络赛 B.Super_Log

测试地址
题意简述:
给定a和k以及m,试求出
a a a . . . m o d &MediumSpace; m a^{a^{a^{...}}} mod \: m aaa...modm
其中共k层幂塔。其中a,k和m小于等于1e6。
解题思路:
首先使用拓展欧拉定理需要 b &gt; φ ( m ) b &gt; \varphi(m) b>φ(m),所以对于不同的b要分类讨论一下。设
f ( a , k , m ) = a a a . . . % m f(a,k,m) = a^{a^{a^{...}}} \% m f(a,k,m)=aaa...%m
其中a是有k层的幂塔。

  1. 首先,当a = 1或者b = 0时特判,得出答案为 1%m。
  2. 本题中b = f(a, k-1,INF),如果a >= phi(m),那么显然b一定大于phi(m),即满足拓展欧拉定理中第3种情况;
  3. 如果k = 1,则b = f(a,k-1,INF) = 1,此时只需判断phi(m)是否大于1即可判断当然情况符合拓展欧拉定理第3还是第2种情况。
  4. 剩下的情况我们就可以通过递归来判断b是否大于phi(m),因为若b >= phi(m),那么 l o g a b &gt; = l o g a p h i ( m ) log_ab &gt;= log_a phi(m) logab>=logaphi(m)

代码示例:

#include<cstdio>
#include<cmath>
typedef long long ll;
const int N = 1e6+10;
ll qpow(ll a,ll b,ll m){
	ll res = 1;
	while(b){
		if(b&1) res = res*a%m;
		a = a*a%m;
		b >>= 1;
	}
	return res;
}
int v[N],primes[N],phi[N];
int init(){
	int cnt = 0;
	for(int i = 2;i < N;i++){
		if(!v[i]){
			primes[cnt++] = i;
			v[i] = i;
			phi[i] = i-1;
		}	
		for(int j = 0;j < cnt;j++){
			if(primes[j] > v[i] || primes[j]*i >= N)
				break;
			v[i*primes[j]] = primes[j];
			phi[i*primes[j]] = phi[i]*(i%primes[j] ? primes[j]-1 : primes[j]);
		}
	}
}
ll gcd(ll a,ll b){
	if(b == 0) return a;
	return gcd(b,a%b);
}
bool check(ll a,ll b,ll p){
	if(b == 0) return p <= 1;	//f(a,0,p) = 1
	if(a >= p) return true;//f(a,b,INF) > p
	return check(a,b-1,log(p)/log(a)); 
}
ll f(ll a,ll b,ll m){
	if(m == 1) return 0;		//递归终止条件1,此时之后答案恒为0 
	if(b <= 1) return qpow(a,b,m);//递归终止条件2 
	ll ph = phi[m];
//	printf("%lld\n",ph);
	if(gcd(a,m) == 1) return qpow(a,f(a,b-1,ph),m);	//欧拉定理 
	if(check(a,b-1,ph)) return qpow(a,f(a,b-1,ph)+ph,m);//拓展欧拉定理情况1 
	return qpow(a,f(a,b-1,ph),m); 		//拓展欧拉定理情况2 
}
ll a,b,m;
int t;
int main(){
	scanf("%d",&t);
	init();
	while(t--){
		scanf("%lld%lld%lld",&a,&b,&m);
		printf("%lld\n",f(a,b,m));
	}
	return 0;
}
参考资料
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迷亭1213

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值