(luogu4139) 上帝与集合的正确用法

原题链接

思路:

由扩展欧拉定理,有:

\[ 2^{2^{2\cdots}} \equiv 2^{(2^{2\cdots} \mod \varphi(p)) + \varphi(p)}\pmod p \]

上面的 \(2^{2\cdots} \mod \varphi(p)\) 可以递归求解,当 \(\varphi(p)\) 减小到 1 即可回溯.

至于 \(\varphi(p)\), 用线性筛预处理即可.

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <cstdio>
#include <vector>
using namespace std;
const int Mp(10000050);
int phi[Mp];
vector<int> prm;
void euler() { //线性筛
phi[1] = 0;
for(int i(2);i<Mp;++i) {
if(!phi[i]) {
phi[i] = i-1;
prm.push_back(i);
}
for(int j(0);j<prm.size() && 1ll*i*prm[j]<Mp;++j) {
if(i%prm[j]==0) {
phi[i*prm[j]] = phi[i]*prm[j];
break;
} else {
phi[i*prm[j]] = phi[i]*(prm[j]-1);
}
}
}
}

int ksm(int a,int b,int p) { //快速幂
int ret(1),tmp(a%p);
for(int i(0);(1<<i)<=b;++i) {
if(b&(1<<i)) {
ret = 1ll*ret*tmp%p;
}
tmp = 1ll*tmp*tmp%p;
}
return ret;
}
int ans(int p) { //递归求解
if(p<=1) { //边界条件
return 0;
} else {
return ksm(2,ans(phi[p])+phi[p],p);
}
}

int main() {
euler();
int T;
scanf("%d",&T);
while(T--) {
int n;
scanf("%d",&n);
printf("%d\n",ans(n));
}
return 0;
}