CF906D Power Tower

感觉没啥好说的,只要你知道扩展欧拉定理的式子就很 trivial 的一个题

幂塔类的问题都考虑用扩展欧拉定理降幂,则每往指数上操作一层复杂度模数就会从 \(m\) 变为 \(\phi(m)\)

根据经典结论可知,该过程在大约 \(\log m\) 次操作后就会让模数变为 \(1\),此时后面的部分就无需再计算了

不过要注意在使用扩展欧拉定理时需要对快速幂略作修改,当求出的结果 \(t\ge \phi(m)\) 时要变为 \(t\bmod \phi(m)+\phi(m)\)

总复杂度 \(O(q\log^2 m)\)

#include<cstdio>
#include<iostream>
#include<map>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,mod,a[N],q,l,r; map <int,int> phi;
inline int get_phi(int n)
{
    if (n==1) return 1;
    if (phi.count(n)) return phi[n];
    int tmp=n,ret=n;
    for (RI i=2;i*i<=n;++i)
    if (n%i==0)
    {
        ret=ret/i*(i-1);
        while (n%i==0) n/=i;
    }
    if (n>1) ret=ret/n*(n-1);
    return phi[tmp]=ret;
}
inline int quick_pow(int x,int p,int mod,int mul=1)
{
    for (;p;p>>=1)
	{
		if (p&1)
    	{
    	    if (1LL*mul*x>=mod) mul=1LL*mul*x%mod+mod; else mul=1LL*mul*x;
    	}
    	if (1LL*x*x>=mod) x=1LL*x*x%mod+mod; else x=1LL*x*x;
    }
    return mul;
}
inline int solve(CI l,CI r,CI mod)
{
    if (l>r||mod==1) return 1;
    int p=solve(l+1,r,get_phi(mod));
    return quick_pow(a[l],p,mod);
}
int main()
{
    RI i; for (scanf("%d%d",&n,&mod),i=1;i<=n;++i) scanf("%d",&a[i]);
    for (scanf("%d",&q);q;--q)
    scanf("%d%d",&l,&r),printf("%d\n",solve(l,r,mod)%mod);
    return 0;
}
posted @ 2024-07-24 20:10  空気力学の詩  阅读(16)  评论(0编辑  收藏  举报