Loading

题解-洛谷P4139 上帝与集合的正确用法

上帝与集合的正确用法

\(T\) 组数据,每次给定 \(p\),求

\[\left(2^{\left(2^{\left(2^{\cdots}\right)}\right)}\right)\bmod p \]

数据范围:\(1\le T\le 1000\)\(1\le p\le 10^7\)


这篇题解主要是给自己看的,因为小蒟蒻从未见过这种骚操作。


首先这个式子虽是无限的,但是答案是固定的。

  • 先来几个引理

\[a^{\varphi(p)}\equiv1\pmod p \]

\[a^b\equiv a^{(b\bmod \varphi(p))+\varphi(p)}\pmod p \]

所以上面那个递归式可以转化:

\[2^{\left(2^{\left(2^{\cdots}\right)}\right)}\equiv 2^{\left(2^{\left(2^{\cdots}\right)}\bmod\varphi(p)\right)+\varphi(p)}\pmod p \]

所以可以先求 \(\left(2^{\left(2^{\left(2^{\cdots}\right)}\right)}\right)\bmod \varphi(p)\),又可以先求 \(\left(2^{\left(2^{\left(2^{\cdots}\right)}\right)}\right)\bmod \varphi(\varphi(p))\)……最终一直递归下去。

\[\because \begin{cases} \varphi(1)=1\\ \varphi(p)<p&p>1\\ \end{cases}\\ \therefore \varphi(\varphi(\varphi(\cdots\varphi(p)\cdots)))=1\\ \]

因为 \(\left(2^{\left(2^{\left(2^{\cdots}\right)}\right)}\right)\bmod 1=0\),所以递归有边界了,可以开码了。


时间复杂度 \(\Theta({\rm max}p+T\log^2 p)\)


  • 代码:
#include <bits/stdc++.h>
using namespace std;

//Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x(a) a.first
#define y(a) a.second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

//Data
const int N=1e7;

//Sieve
bitset<N+7> np;
int phi[N+7];
vector<int> pr;
void Sieve(){
	np[1]=phi[1]=1;
	for(int i=2;i<=N;i++){
		if(!np[i]) pr.pb(i),phi[i]=i-1;
		for(int p:pr)if(i*p<=N){
			np[i*p]=1;
			if(i%p==0){phi[i*p]=phi[i]*p;break;}
			phi[i*p]=phi[i]*phi[p];
		} else break;
	}
} 

//Pow
int Pow(int a,int x,int mod){
	if(a==0) return 0; int res=1;
	for(;x;a=1ll*a*a%mod,x>>=1)if(x&1) res=1ll*res*a%mod;
	return res;
}
int Jump(int p){ // 两行核心代码
	if(p==1) return 0;
	return Pow(2,Jump(phi[p])+phi[p],p); 
}

//Main
int main(){
	int t; scanf("%d",&t);
	Sieve();
	for(int ti=1;ti<=t;ti++){
		int p; scanf("%d",&p);
		printf("%d\n",Jump(p));
	}
	return 0;
}

祝大家学习愉快!

posted @ 2020-05-12 15:16  George1123  阅读(124)  评论(0编辑  收藏  举报