1. 程式人生 > >[洛谷P4139]上帝與集合的正確用法

[洛谷P4139]上帝與集合的正確用法

題目大意:多次詢問,每次給你$p$詢問$2^{2^{2^{\dots}}}\bmod p$

題解:擴充套件尤拉定理,求出$\varphi(p)$即可。因為$2^{2^{2^{\dots}}}>>p$,所以其實每一次算的時候都可以直接加上$\varphi(p)$,不用判斷

卡點:

 

C++ Code:

#include <cstdio>

namespace Math {
	const int N = 1e7 + 1;

	int pri[N], ptot, phi[N];
	bool notp[N];
	inline void sieve() {
		phi[1] = 1;
		for (int i = 2; i < N; i++) {
			if (!notp[i]) phi[pri[ptot++] = i] = i - 1;
			for (int j = 0, t; j < ptot && (t = i * pri[j]) < N; j++) {
				notp[t] = true;
				if (i % pri[j] == 0) {
					phi[t] = phi[i] * pri[j];
					break;
				}
				phi[t] = phi[i] * phi[pri[j]];
			}
		}
	}

	inline long long pw(int b, int p, const int mod) {
		long long res = 1, base = b, tmp = 0;
		for (; p; p >>= 1) {
			if (p & 1) {
				res = res * base;
				if (res >= mod) tmp = mod, res %= mod;
			}
			base = base * base;
			if (base >= mod && p >> 1) tmp = mod, base %= mod;
		}
		return res + tmp;
	}
}
using Math::phi;

int Tim, p;
long long solve(int p) {
	if (p == 1) return p;
	return Math::pw(2, solve(phi[p]), p);
}
int main() {
	Math::sieve();
	scanf("%d", &Tim);
	while (Tim --> 0) {
		scanf("%d", &p);
		printf("%lld\n", solve(p) % p);
	}
	return 0;
}