題解 洛谷P4139 上帝與集合的正確用法
阿新 • • 發佈:2021-01-12
題目描述:
求 \(2^{2^{2^{\cdots}}}\bmod p\) 的值。
\(T\) 組資料, \(1\leq T \leq 10^3 ,1\leq p \leq 10^7\) 。
前置知識:
尤拉定理:若 \(a,p\) 互質,則 \(a^b \bmod p = a ^{b \bmod \varphi(p)}\bmod p\) 。
拓展尤拉定理:若不保證 \(a,p\) 互質,則:
\[a^b \bmod p= \begin{cases} a^b (b < \varphi(p)) \\ a^{b \bmod \varphi(p)+\varphi(p)} (b \geq \varphi(p)) \end{cases} \]Solution
看到這個無解的式子,我們考慮拓展拉定理求解。
因為這個式子有無限個,所以 \(b\) 遠遠大於 \(\varphi(p)\) ,所以要使用上面 \(a^b \bmod p=a^{b \bmod \varphi(p)+\varphi(p)}\) 這個公式
我們可以把原式子變成:
\[2^{2\bmod \varphi(p)+\varphi(p)^{2\bmod \varphi(\varphi(p))+\varphi(\varphi(p))}\cdots} \]發現這是個遞迴的式子,為了方便,我們設:
\[f(p) = 2^{2^{2^{\cdots}}} \bmod p \]這樣,根據拓展尤拉定理:
邊界是 \(p=1\) 時,返回 \(0\) ,這是因為,當 \(p=1\) 是,任何數除以 \(1\) 的餘數都是 \(0\) 。
剩下的可以用快速冪來解決。
程式碼如下:
#include <cstdio> #include <cstring> #include <cctype> #define int long long inline int read() { int num = 0 ,f = 1; char c = getchar(); while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar(); while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar(); return num * f; } const int N = 1e7 + 5; int prime[(int)(1e6) + 5] ,cnt; bool isprime[N]; int phi[N]; inline void Prime(int n) { //線性篩求 phi memset(isprime ,true ,sizeof(isprime)); isprime[0] = isprime[1] = false; phi[1] = 1; for (int i = 2;i <= n; i++) { if (isprime[i]) { prime[++cnt] = i; phi[i] = i - 1; } for (int j = 1;j <= cnt && i * prime[j] <= n; j++) { isprime[i * prime[j]] = false; if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; } phi[i * prime[j]] = phi[i] * (prime[j] - 1); } } } inline int pow(int a ,int b ,int p) { //calculate a ^ b mod p int ans = 1 % p; while (b) { if (b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; } inline int solve(int p) { //計算 2 的 2 的 2 的 2 ...... 次方 if (p == 1) return 0; //邊界 return pow(2 ,solve(phi[p]) + phi[p] ,p); // 把公式抄下來 } int T ,p; signed main() { Prime(1e7); //一定要先預處理,不然...... T = read(); while (T--) { p = read(); printf("%lld\n" ,solve(p)); } return 0; }