bzoj 3884 上帝与集合的正确用法【欧拉函数】

题目链接:

http://www.lydsy.com/JudgeOnline/problem.php?id=3884

题意:

定义$f(p)=2^{2^{2^{2^{…^2}}}}( mod p)$,求$f(p)$,其中$2$有无穷多个,$1 leq p leq 10^{7}$。

分析:

已知$$a^b%p=(a%p)^{phi(p) + b % phi(p)} % p$$
那么$$f(p)=(2 % p)^{2^{2^{2^{…^2}}}%phi(p)+phi(p)}% p$$
即$$f(p)=(2%p)^{f(phi(p))+phi(p)} % p$$
根据 $n为奇数,phi(2n)=phi(n),n为偶数,phi(2n)=2phi(n)$,总是可以转化成一半处理,在$O(logp)$内变为$1$,$f(1)=0$,递归截止。
加上因式分解求欧拉函数总体时间复杂度$O(logpsqrt 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
> File Name: 3884.cpp
> Author: jiangyuzhu
> Created Time: 2016/8/30 19:08:42
************************************************************************/
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
int (int n)
{
int res = n;
for(int i = 2; i * i <= n; i++){
if(n % i == 0){
res = res / i * (i - 1);
while(n % i == 0) n /= i;
}
}
if(n != 1) res = res / n * (n - 1);
return res;
}
int quick_pow(int b, int a, int p)
{
ll res = 1;
for(; a; a >>= 1, b = b * 1ll * b % p){
if(a & 1) res = res * 1ll * b % p;
}
return res;
}
int a2;
int dfs(int p)
{
if(p == 1) return 0;
int np = euler(p);
return quick_pow(a2, dfs(np) + np, p);
}
int main (void)
{
int T;scanf("%d", &T);
while(T--){
int p;scanf("%d", &p);
a2 = 2 % p;
printf("%dn", dfs(p));
}
return 0;
}