[CodeForces - 906D] Power Tower——扩展欧拉定理

题意

给你 $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

猜你喜欢

转载自www.cnblogs.com/lfri/p/11445887.html