题意
给你 $n$ 个数 $w$ 和一个数 $p$,$q$个询问,每次询问一个区间 $[l,r] $,求 $w_l^{(w_{l+1}^{(w_{l+2}…^{w_r})})}\mod p$.
分析
由扩展欧拉定理:
$$a^b\equiv \begin{cases} a^{b\%\phi(p)}~~~~~~~~~~~gcd(a,p)=1\\ a^b~~~~~~~~~~~~~~~~~~gcd(a,p)\neq1,b<\phi(p)\\ a^{b\%\phi(p)+\phi(p)}~~~~gcd(a,p)\neq1,b\geq\phi(p) \end{cases}~~~~~~~(mod~p)$$
与BZOJ 3384中,次方是无限的,所以说指数一定大于 $\varphi(p)$,但是这道题中指数不一定大于 $\varphi(p)$,需要重写 Mod。
phi需要记忆话,不然会超时。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; ll n, p, a[maxn]; unordered_map<int, int>phi; ll Mod(ll x, ll mod) { return x < mod ? x : x % mod + mod; } ll euler_phi(ll n) { ll m = (ll)sqrt(n + 0.5); ll ans = n; for (ll i = 2; i <= m; i++) { if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; //除尽 } } if (n > 1) ans = ans / n * (n - 1); //剩下的不为1,也是素数 return ans; } ll get_phi(ll x) { if(phi[x]) return phi[x]; return phi[x] = euler_phi(x); } ll qpow(ll a, ll b, ll p) { ll ret = 1; while(b) { if(b&1) ret = Mod(ret * a, p); a = Mod(a * a ,p); b >>= 1; } return ret; } ll cal(ll l, ll r, ll p) //a^a^a..^a共b次 { //printf("%lld %lld\n", t, p); //if(t == 1) return Mod(a, p); if(l == r) return Mod(a[l], p); if(p == 1) return Mod(a[l], p); ll phip = get_phi(p); return qpow(a[l], cal(l+1, r, phip), p); //第一类和第三类 } int main() { scanf("%I64d%I64d", &n, &p); for(int i = 1;i <= n;i++) scanf("%I64d", &a[i]); int q; scanf("%d", &q); while(q--) { ll l, r; scanf("%I64d%I64d", &l, &r); printf("%I64d\n", cal(l, r, p) % p); //这个取模不能少 } return 0; }
参考链接:
1. https://blog.csdn.net/Charlie_jilei/article/details/79252689
2.https://blog.csdn.net/qq_35914587/article/details/79883547
原文地址:https://www.cnblogs.com/lfri/p/11445887.html
时间: 2024-10-02 09:52:59