当前位置: 首页 > news >正文

幂塔问题-扩展欧拉函数

嵌套幂模运算问题(基于扩展欧拉定理)


问题背景

给定一个数组 \(w\)、模数\(m\) 和若干查询 \([l, r]\),要求计算**嵌套幂表达式

\[w_l^{\overset{w_r}{\overset{^{\cdot^{\cdot^{\cdot}}}}{^{w_{l+1}}}}} \mod m \]

的结果。由于嵌套幂的指数过大( 到了1e9 ),直接计算不可行,须依赖结合快速幂和扩展欧拉定理进行降幂求解。

扩展欧拉定理

在讲解代码前,需先明确扩展欧拉定理的核心内容。定理分为三种情况(对应代码注释中的分类):
对于任意正整数 \(a, b, m\),设 \(φ(m)\)\(m\) 的欧拉函数(1~m 中与 m 互质的数的个数),则:

  1. \(gcd(a, m) = 1\)(a 与 m 互质): \(a^b \equiv a^{b \mod \varphi(m)} \mod m\)
    (原本的欧拉定理,互质时无需考虑指数大小)
  2. \(gcd(a, m) ≠ 1\)\(b < \varphi(m)\) $a^b \equiv a^b \mod m $
    (指数较小时,直接计算,无需降幂)
  3. \(gcd(a, m) ≠ 1\)\(b \ge \varphi(m)\) \(a^b \equiv a^{(b\mod \varphi(m)) + \varphi(m)} \mod m\)
    (指数较大时,降幂后需\(φ(m)\),避免不互质导致的结果错误)

证明-oi-wiki

实在太长了,自己看吧但写的真的是能看到最好的了

使用细节-董老师视频已跳过欧拉定理

关键性质:对于 \(m ≥ 2\)\(φ(m) < m\),且 \(φ(φ(m)) < φ(m)\),即欧拉函数序列 \(m → φ(m) → φ(φ(m)) → ...\) 会快速递减至 1,最终递归终止(任何数 mod 1 都为 0)。

实现过程

由于\(mod<=1e9\),所以我们采用素数加速计算(更优的直接筛\(φ\)空间不够),我们通过递推计算每一层的\(a^b \mod m\),(在快速幂中,详见代码及注释)判断是否要加m后,将值传给下一层。最后得出答案再对m取模。

code

含较详细注释

#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 1e6+10;int pri[maxn];
bool not_pri[maxn];
int phi[maxn];// phi[i]存计算得到的第i个phi
int wi[maxn];/**
扩展欧拉定理:
1: a^b = a^(b % phi[m])  mod m    ---gcd(a,m)=1
2: a^b = a^b mod m    ---gcd(a,m)!=1 && b<phi[m]
3: a^b = a^(b % phi[m] + phi[m]) mod m   ---b>=phi[m]   可以包含1
证明详见 oi-wiki
*/void sieve(int n)// 线性质数筛,加速单个phi的求解速度
{not_pri[1]=1;for(int i=2;i<=n;++i){if(!not_pri[i]){pri[++pri[0]]=i;}for(int j=1;j<=pri[0] && i*pri[j]<=n;++j){not_pri[i*pri[j]]=1;if(!(i%pri[j])){break;}}}
}int get_phi(int n)// 求单个phi
{int ret=n;// 初始化为自己for(int i=1;i<=pri[0] && pri[i]*pri[i]<=n ;++i)// 若有大于sqrt(n)的质因数,最多只有1个,后续单独处理{if(!(n%pri[i])){ret=ret/pri[i]*(pri[i]-1);// 等价于*(1-1/pri[i])while(!(n%pri[i]))// 避免后续重复处理{n/=pri[i];}}}if(n!=1){ret=ret/n*(n-1);//剩余的n是一个大于sqrt(原n)的质因数}return ret;
}int fa_pow(int base,int ci,int mod)// 扩展欧拉函数的快速幂
{/*这里的base是某一层的底数a,ci(次)是指数(处理后的)b,mod是m我们在做快速幂的时候要判断:是否要对当前的返回值(下一层的b)要加m(下一层m的phi[m])*/int ret=1;while(ci){if(ci&1){ret*=base;if(ret>=mod){ret=ret%mod+mod;// 超过后取模并加m}}base*=base;if(base>=mod){base=base%mod+mod;// 可能还未更新到ret,要保留当前状态,保证下一次更新ret时能打上标记}ci>>=1;}return ret;
}int solve(int l,int r,int cnt)
{/*三个递归出口,1.石块用完了--l==r2.phi[cnt]=1,后面不管再有多少指数,取模后的结果都相同3.石子本身为1,不管多少指数都是他本身*/if(!phi[cnt+1]){phi[cnt+1]=get_phi(phi[cnt]);}if(phi[cnt]==1){return 1;// 约等于取模后加phi[cnt]}if(wi[l]==1){return 1;}if(l==r)// 最后一层,判断是那种情况{if(wi[r]>=phi[cnt]){return wi[r]%phi[cnt]+phi[cnt];}else{return wi[r];}}return fa_pow(wi[l],solve(l+1,r,cnt+1),phi[cnt]);// a^b mod m
}void read(int &x)// 本题卡常
{int f=1;x=0;char c=getchar();while(c<'0'||c>'9'){if(c=='-'){f=-1;}c=getchar();}while(c>='0' && c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}x*=f;
}signed main()
{sieve(maxn);int n,m,q;read(n);read(m);for(int i=1;i<=n;++i){read(wi[i]);}read(q);int l,r;phi[1]=m;//数组第一个存它自己for(int i=1;i<=q;++i){read(l);read(r);printf("%lld\n",solve(l,r,1)%m);//结果可能有+m表示使用第三条式子,所以要取模}return 0;
}

有问题欢迎讨论

http://www.gsyq.cn/news/45540.html

相关文章:

  • 手持贴标机生产源头厂家2025年市场洞察
  • 奶牛抗议-二维偏序优化
  • 4G摄像机国标GB28181接入EasyGBS突然不上线?双网卡智能切换惹的锅!
  • 详细介绍:热门编程语言的排名及开源贡献比例表格-截至2025年10月
  • SQLite 连接串说明
  • 完整教程:深度学习实战:从图像分类到自然语言处理的完整指南
  • 【完整源码+内容集+部署教程】 黄瓜叶片检测系统源码和数据集:改进yolo11-RVB
  • 国产化Word处理控件Spire.Doc教程:使用Java将RTF文件转换为PDF的全面教程
  • 2025年门卫室岗亭源头厂家综合实力榜单:形象岗亭/小区值班岗亭/钢结构吸烟亭源头厂家精选
  • 树莓派性能分析脚本
  • 2025 ICPC 南京站 游记
  • windows客户端配置免密上传代码到gitlab
  • 神级项目,Github 上线封神,BettaFish你不可忽视的多Agent舆情分析神器~~~
  • MyEMS:赋能能源精细化管理的智慧引擎
  • 2025年新型建筑木方源头厂家综合实力榜单:建筑施工模板/覆膜建筑模板/清水覆膜板生产厂家精选
  • 开源能源管理系统:解锁当下能源困局的关键力量
  • 详细介绍:五点法求解相机的相对位姿
  • Gitee:打造本土化技术生态,驱动中国数字化变革新引擎
  • 2025年卫生应急服生产厂家综合实力榜单:卫生应急藏青无领T恤/黑色立领外套/纯棉黑T恤源头厂家精选
  • 2025年11月学习机品牌推荐:家长口碑榜对比十强同步教材与护眼方案
  • Linux crond - Lafite
  • 鸿蒙应用开发实战:应用数据备份恢复
  • 实用指南:[数据结构] 队列实战!火车车厢重排从 0 到 1:缓冲轨巧用 + 可运行代码
  • Kerberos常见工具错误解析与修复指南
  • vim 配置
  • HT-LFCG-3400+,0改版,测试数据贴图
  • C# 基础——async/await 的实现原理与最佳实践
  • 7885
  • 77777
  • 跳房子 P3957: 单调队列