[luoguP4139]上帝与集合的正确用法

\(\text{Description}\)

  • \(\text{Given a number }p(p\leqslant10^7).\)
  • \(\text{Output }2^{2^{2^{2^{\cdots}}}}\bmod p.\)

\(\text{Method}\)

\(\text{Use ex-Euler's Theorem}\quad b\geqslant\varphi(m)\Rightarrow a^b\equiv a^{b\bmod\varphi(m)+\varphi(m)}\pmod{m}.\)

\(\text{Let }x=2^{2^{2^{2^{\cdots}}}}.\)

\[\begin{aligned}x\bmod p& =2^x\bmod p\\& =2^{x\bmod \varphi(p)+\varphi(p)}\bmod p\\& =2^{2^x\bmod \varphi(p)+\varphi(p)}\bmod p\\& =2^{2^{x\bmod \varphi(\varphi(p))+\varphi(p)}\bmod \varphi(p)+\varphi(p)}\bmod p\\&=\cdots\end{aligned}\]

\(\text{Use recursion algorithm.}\)


\(\text{Code}\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int qmul(int a,int b,int mod)
{
    if(a==0||b==0||mod==1ll)return 0;
    if(b==1ll)return a%mod;
    int ans=qmul(a,b/2ll,mod);
    ans+=ans,ans%=mod;
    if(b%2ll)ans+=a,ans%=mod;
    return ans;
}
int qpow(int a,int b,int mod)
{
    if(a==0||mod==1ll)return 0;
    if(b==0)return 1ll;
    int ans=qpow(a,b/2ll,mod);
    ans=qmul(ans,ans,mod),ans%=mod;
    if(b%2ll)ans=qmul(ans,a,mod),ans%=mod;
    return ans;
}
int v[10000010],prime[10000010],phi[10000010];
void lineareuler(int n)
{
    memset(v,0,sizeof(v));
    int cnt=0;
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)
        {
            v[i]=i;
            prime[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt;j++)
        {
            if(prime[j]>v[i]||prime[j]>n/i)break;
            v[i*prime[j]]=prime[j];
            phi[i*prime[j]]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
        }
    }
    return;
}
int calc(int xx)
{
    if(xx==1)return 0;
    else return qpow(2,calc(phi[xx])+phi[xx],xx);
}
int t,p;
int main()
{
    scanf("%d",&t);
    lineareuler(10000000);
    for(int qwerty=1;qwerty<=t;qwerty++)
    {
        scanf("%d",&p);
        printf("%d\n",calc(p));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pjykk/p/12043660.html