P4139 上帝与集合的正确用法
P4139 上帝与集合的正确用法
题目大意
定义 \(a_0=1,a_n=2^{a_{n-1}}\),可以证明 \(a_n\bmod p\) 在 \(n\) 足够大时为常数,求这个常数。
分析
利用了,扩展欧拉定理
- \(b \geq \phi(p)\ a^b \equiv a^{b\ mod\ \phi(p)+\phi(p)}(mod\ p)\)
- \(b < \phi(p)\ a^b \equiv a^{b\ mod\ \phi(p)}(mod\ p)\)
其中a,p
可以不互质。
利用这个式子,可以快减少幂的大小。
接下来,我们递归的求出结果就好
时间复杂度\(O(\log^2 p)\)
Ac_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
const int N = 1e7 + 10;
int n;
int phi[N],Primes[N],cnt;
bool st[N];
void get_eulers()
{
phi[1]=1;
for(int i=2;i<N;i++)
{
if(!st[i]) Primes[cnt++]=i,phi[i]=i-1;
for(int j=0;Primes[j]*i<N;j++)
{
st[Primes[j]*i]=1;
if(i%Primes[j]==0)
{
phi[Primes[j]*i]=phi[i]*Primes[j];
break;
}
else phi[i*Primes[j]]=phi[i]*(Primes[j]-1);
}
}
}
int ksm(int a,int b,int mod)
{
int res = 1;
while(b)
{
if(b&1) res = 1l*res*a%mod;
b>>=1;
a = 1ll*a*a%mod;
}
return res;
}
int get(int p)
{
if(p==1) return 0;
return ksm(2,get(phi[p])+phi[p],p);
}
int main()
{
ios;
get_eulers();
int T;cin>>T;
while(T--)
{
int p;cin>>p;
cout<<get(p)<<'\n';
}
return 0;
}