传送门
题意:求 2(2(2...))modp 的值,多组询问。 p107

Solution:

根据扩展欧拉定理,我们知道:

bφ(p) 时, abab%φ(p)+φ(p)modp

此公式的具体证明可以百度扩展欧拉定理

我们假设 f(p)=2(2(2...))modp ,那么 f(1)=0

由公式可得:

f(p)=2(2(2...))modp

=2(2(2(2...))%φ(p)+φ(p))modp

=2f(φ(p))+φ(p)modp

由此我们就得到了 f(p) 的递推式

但是这样复杂度可能有问题?

我们来大力分析一波:

如果p为偶数,根据计算公式 φ(x)=xni=1(pi1pi) ,我们一定会乘上一个 12 ,所以说 φ(x)x2

如果p为奇数,那么他定会包含奇质因子,再结合公式,一定会乘一个偶数,所以说 φ(x) 一定会是偶数

由这些我们就可以知道,我们递归一次只需要 O(logn) 的复杂度,因此总复杂度 O(Tplogp)

代码:

#include<cstdio>
#include<iostream>
using namespace std;
int t,n;
bool vis[10000010];
int F[10000010];
int fast_pow(int a,int x,int mod)
{
    int ans=1;
    for (;x;x>>=1,a=1ll*a*a%mod)
        if (x&1) ans=1ll*ans*a%mod;
    return ans;
}
int phi(int x)//根据公式进行计算
{
    int ret=x;
    for (int i=2;i*i<=n;i++)
    {
        if (x%i==0)
        {
            ret-=ret/i;
            while (x%i==0)
                x/=i;
        }
    }
    if (x>1) ret-=ret/x;
    return ret; 
}
int f(int x)
{
    if (vis[x]) return F[x];
    int p=phi(x);
    vis[x]=1;
    return F[x]=fast_pow(2,f(p)+p,x);
}
int main()
{
    scanf("%d",&t);
    vis[1]=1;F[1]=0;
    while (t--)
    {
        scanf("%d",&n);
        printf("%d\n",f(n));
    }
}