[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\\&=\cdots\end{aligned}
\]
\(\text{Use recursion algorithm.Let }f(i)=x\bmod i.\)
\[f(i)=\begin{cases}0&i=1\\2^{f(\varphi(i))+\varphi(i)}\bmod i&i>1\end{cases}
\]
\(\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;
}