【题解】上帝与集合的正确用法

\([题目链接](https://www.luogu.org/problem/P4139)\)

前置芝士 欧拉函数

题目大意:求\(2^{2^{2^...}}\) \(mod\) \(p\)的值。

第一眼看上去好像不可做的样纸,但是我们有一个定理:

\(b>φ(p)\)时有\(a^b \equiv a^{b \text{ mod } \varphi(p)+\varphi(p)} (\text{mod } p)\)

\(b<φ(p)\)时,后面就不需要加\(φ(p)\).

那么这题可以看出一个递归雏形。我们可以用筛法将欧拉函数筛出来,筛到题目给的\(p\)的范围即可。

然后按照题意递归。最好有快速幂和龟速乘。

\(Code:\)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=1e7;
int T,p,phi[MAXN+10];
void Init(){
	phi[1]=1;
	for(int i=2;i<=MAXN;++i){
		if(!phi[i])
			for(int j=i;j<=MAXN;j+=i){
				if(!phi[j])phi[j]=j;
				phi[j]=phi[j]/i*(i-1);
			}
	}
}
inline int F_Mul(int a,int b,int m){
	int res=0;
	while(b){
		if(b&1)res=res+a,res%=m;
		b>>=1,a<<=1,a%=m;
	}
	return res;
}
inline int Fast(int a,int b,int m){
	int ans=1;
	while(b){
		if(b&1)ans=F_Mul(ans,a,m);
		b>>=1;a=F_Mul(a,a,m)%m;
	}
	return ans;
}
inline int solve(int p){
	if(p==1)return 0;
	return Fast(2,solve(phi[p])+phi[p],p);
}
int main(){
	Init();
	scanf("%d",&T);
	while(T--){
		scanf("%d",&p);
		printf("%d\n",solve(p));
	}
	return 0;
}
posted @ 2019-09-26 22:02  Refined_heart  阅读(134)  评论(0编辑  收藏  举报