[luogu4139]上帝与集合的正确用法欧拉定理+扩展欧拉定理
Posted chhokmah
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu4139]上帝与集合的正确用法欧拉定理+扩展欧拉定理相关的知识,希望对你有一定的参考价值。
题目大意
让你求\(2^{2^{2^{\cdots}}}(mod)P\)的值。
前置知识
知识1:无限次幂怎么解决
让我们先来看一道全国数学竞赛的一道水题:
让你求解:\(x^{x^{x^{\cdots}}}=2\)方程的解。
对于上面的无限次幂,我们可以把这个式子移上去,得到了\(x^{2}=2\)。
因为指数的原因,所以我们可以直接得到了\(x=\sqrt{2}\)。
以上的问题,启示我们对于这一些无限次幂可以转移来解决。
以上的东西可能用不到
知识2:欧拉定理和扩展欧拉定理
详细请出门左拐洛谷模板区【传送门】。(从入门到入土)
因为这一道题目\(p\)为任意整数,那么无法使用欧拉定理,那么就用比欧拉定理稍微复杂一点点的扩展欧拉定理。
简单介绍一下扩欧定理:
\[a^b\equiv a^{(b\mod\varphi(m))+\varphi(m)}\mod m\]
条件是\(b>= \varphi(m)\)
给一份蒟蒻的线性筛欧拉函数的代码
inline void Get_Phi(int MAXN) {
phi[1] = 1;
for (int i = 2; i <= MAXN; i ++) {
if (!vis[i]) prime[++ Prime_tot] = i, phi[i] = i - 1;
for (int j = 1; j <= Prime_tot && i * prime[j] <= MAXN ; j ++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; }
else phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
}
正解
既然我们知道了欧拉公式,那么我们就可以代到原来的幂次中,得到以下的推导:
\[2^{2^{2^{\cdots}}} \ mod \ p = 2^{2^{2^{\cdots}} mod \ \varphi(p) + \varphi(p)}\ mod \ p\]
很明显的是\(\varphi(1)=0\),那么这个就是我们递归的边界。
剩下来的幂次我们可以用快速幂实现。
欧拉函数的筛法就用线性筛就可以了,好像这一道题目就只用单个的筛好像可以更快。
时间复杂度:\(O(T+T\times log_2^p)\)
代码
#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define db double
#define N 10000500
using namespace std;
template <typename T>
inline void read(T &x) {
x = 0; T fl = 1; char ch = 0;
for (; ch < '0' || ch > '9'; ch = getchar())
if (ch == '-') fl = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
x = (x << 1) + (x << 3) + (ch ^ 48);
x *= fl;
}
template <typename T>
inline T Power(T x, T y, T Mod) {
T res = 1;
for (; y; y >>= 1) {if (y & 1) res = (res * x) % Mod; x = (x * x) % Mod;}
return res % Mod;
}
ll a, b, c;
ll Prime_tot = 0;
int phi[N], prime[N];
bool vis[N];
inline void Get_Phi(int MAXN) {
phi[1] = 1;
for (int i = 2; i <= MAXN; i ++) {
if (!vis[i]) prime[++ Prime_tot] = i, phi[i] = i - 1;
for (int j = 1; j <= Prime_tot && i * prime[j] <= MAXN ; j ++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; }
else phi[i * prime[j]] = phi[i] * phi[prime[j]];
}
}
}
ll f(ll x) {
if (x == 1) return 0;
else return Power(2ll, f(phi[x]) + phi[x], x);
}
int main() {
int cas; read(cas);
Get_Phi(1e7+1);
while (cas --) {
ll n; read(n);
printf("%lld\n", f(n));
}
return 0;
}
以上是关于[luogu4139]上帝与集合的正确用法欧拉定理+扩展欧拉定理的主要内容,如果未能解决你的问题,请参考以下文章