扩展欧拉定理
据说可以用来解决循环节问题
循环又分纯循环和混循环
纯循环:
如ax%b 它的循环节就是b/gcd(a,b),那么x在[0,b)之内就有gcd(a,b)个取值
(a,b互质就是纯循环,不互质就是混循环)
混循环:
循环节前面的一段尾巴来自于共有的约数p,是log级别的
循环节长度是phi(b)的约数
这道题就是一个扩展欧拉定理的应用
当a,b互质的时候它是一个纯循环,就可以直接把指数不断%phi(p)
当a,b不互质的时候,要把指数%phi(p)再加上phi(p)(当指数大于phi(p)时)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 1000001
#define LL long long
using namespace std;
int t,p,cnt;
LL pri[700000],phi[maxn];
bool vis[maxn];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void get_phi(){
vis[1]=1; phi[1]=1;
for(int i=2;i<maxn;i++){
if(!vis[i]) pri[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt && i*pri[j]<maxn;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
}
inline LL qpow(LL x,int k,int mod){
LL ret=1;
while(k){
if(k&1) (ret*=x)%=mod;
(x*=x)%=mod; k>>=1;
} return ret;
}
inline LL solve(int p){
if(p==1) return 0;
return qpow(2,solve(phi[p])+phi[p],p);
}
int main(){
t=rd();
get_phi(); cout<<cnt<<endl;
while(t--){
p=rd();
printf("%lld\n",solve(p));
}
return 0;
}