Luogu P4139 上帝与集合的正确用法
\(\large{题目链接}\)
\(\\\)
首先介绍一下欧拉定理:
\(\\\)
所以费马小定理其实是欧拉定理的一种特殊情况,即\(p\)为质数时,\(\varphi(p)=p-1\)
\(\\\)
在算法竞赛中我们经常会用到欧拉定理的一个推论:
因为\(a^{b}=a^{\varphi(m) \times \lfloor\frac{b}{\varphi(m)}\ \ \rfloor + b \bmod \varphi(m)}=a^{b \bmod \varphi(m)}\),有了这个推论,即使\(b\)比较大,我们可以依照\(a^{b \bmod \varphi(m)}\)来轻松计算,不过需要\(a\)和\(m\)互质。
\(\\\)
那么如果\(\ \gcd(a,p)\ne 1\)呢,那么我们就要用到扩展欧拉定理(EX)。
\(\\\)
扩展欧拉定理:
若\(b \geqslant \varphi(m)\),\(a^{b}\equiv a^{b\bmod \varphi(m) + \varphi(m)}, \pmod{m},b \geqslant \varphi(m)\),若\(b \leqslant \varphi(m),a^{b} \equiv a^{b \bmod \varphi(m)},\pmod{m}\)。
\(\\\)
讲完前置知识,那我们回到这个题,求\(2^{2^{2^{2^{...}}}}\pmod{p}\),显然\(2^{2^{2^{2^{...}}}}\)是一个很大的数,我们想到用欧拉定理,又题目中没有说明\(p\in prime\),所以我们想到用扩展欧拉定理,只需考虑\(b \geqslant \varphi(p)\)即可。
\(\\\)
\(2^{2^{2^{2^{...}}}} \equiv 2^{2^{2^{2^{...}}} \bmod \varphi(p) + \varphi(p)},\pmod{p}\),这是一个递归过程,我们考虑边界,一定会有\(\varphi(1)=1\)时,此时返回\(2^{x \bmod 1 + 1} = 2 ^ {1}=2\)
\(\\\)
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N = 1e7 + 5;
int t, p, cnt, vis[N], phi[N], pri[N];
int read() {
int x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void varphi() {
phi[1] = 1;
for (int i = 2; i <= N; ++i) {
if (!vis[i]) pri[++cnt] = i, phi[i] = i - 1;
for (int j = 1; j <= cnt && pri[j] * i <= N; ++j) {
vis[i * pri[j]] = 1;
if (i % pri[j] != 0) phi[i * pri[j]] = phi[i] * (pri[j] - 1);
else {
phi[i * pri[j]] = phi[i] * pri[j];
break;
}
}
}
}
inline ull quick_pow(int x, int y, int Mod) {
ull ans = 1, base = x % Mod;
while (y) {
if (y & 1) ans = (ans * base) % Mod;
base = (base * base) % Mod;
y >>= 1;
}
return ans;
}
inline int solve(int Mod) {
//cout << "1";
if (Mod == 1) return 2;
return quick_pow(2, solve(phi[Mod]) + phi[Mod], Mod);
}
int main() {
varphi();
t = read();
while (t--) {
p = read();
printf("%d\n", solve(p));
}
return 0;
}