Miraclys

一言(ヒトコト)

Luogu P4139 上帝与集合的正确用法

\(\large{题目链接}\)
\(\\\)
首先介绍一下欧拉定理:

\[a^{\varphi(p)}\equiv 1\pmod{p}, \gcd(a,p)=1 \]

\(\\\)
所以费马小定理其实是欧拉定理的一种特殊情况,即\(p\)为质数时,\(\varphi(p)=p-1\)
\(\\\)
在算法竞赛中我们经常会用到欧拉定理的一个推论:

\[a^{b}\equiv a^{b \mod \varphi(m)}, \pmod{m},\ \gcd(a,m)=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;
}
posted @ 2022-09-18 16:03  Miraclys  阅读(16)  评论(0编辑  收藏  举报

关于本博客样式

部分创意和图片借鉴了

BNDong

的博客,在此感谢