扩展欧拉定理 [学习笔记]
咕了好久…
对于 \(b \geq \varphi(p)\),有 \(a^b = a^{b\ mod\ \varphi(p)\ +\ \varphi(p)} [mod\ p]\)
其中 \(gcd(a,p)\) 没有要求,也就是可以不互质。
有了这个式子, \(2^{2^{2^{2^{2^{2^{2}}}}}} \% \ p\) 就很好求了,递归就可以了,这里的指数 \(2^{2^{2^{2^{2^{2}}}}} \geq \varphi(p)\) 的,于是直接用就好了QAQ。递归不会超过 \(\log\) 次,所以可以用递归就好了qwq。
// by Isaunoya
#include <bits/stdc++.h>
using namespace std;
#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
const int _ = 1 << 21;
struct I {
char fin[_], *p1 = fin, *p2 = fin;
inline char gc() {
return (p1 == p2) && (p2 = (p1 = fin) + fread(fin, 1, _, stdin), p1 == p2) ? EOF : *p1++;
}
inline I& operator>>(int& x) {
bool sign = 1;
char c = 0;
while (c < 48) ((c = gc()) == 45) && (sign = 0);
x = (c & 15);
while ((c = gc()) > 47) x = (x << 1) + (x << 3) + (c & 15);
x = sign ? x : -x;
return *this;
}
inline I& operator>>(double& x) {
bool sign = 1;
char c = 0;
while (c < 48) ((c = gc()) == 45) && (sign = 0);
x = (c - 48);
while ((c = gc()) > 47) x = x * 10 + (c - 48);
if (c == '.') {
double d = 1.0;
while ((c = gc()) > 47) d = d * 0.1, x = x + (d * (c - 48));
}
x = sign ? x : -x;
return *this;
}
inline I& operator>>(char& x) {
do
x = gc();
while (isspace(x));
return *this;
}
inline I& operator>>(string& s) {
s = "";
char c = gc();
while (isspace(c)) c = gc();
while (!isspace(c) && c != EOF) s += c, c = gc();
return *this;
}
} in;
struct O {
char st[100], fout[_];
signed stk = 0, top = 0;
inline void flush() { fwrite(fout, 1, top, stdout), fflush(stdout), top = 0; }
inline O& operator<<(int x) {
if (top > (1 << 20)) flush();
if (x < 0) fout[top++] = 45, x = -x;
do
st[++stk] = x % 10 ^ 48, x /= 10;
while (x);
while (stk) fout[top++] = st[stk--];
return *this;
}
inline O& operator<<(char x) {
fout[top++] = x;
return *this;
}
inline O& operator<<(string s) {
if (top > (1 << 20)) flush();
for (char x : s) fout[top++] = x;
return *this;
}
} out;
#define pb emplace_back
#define fir first
#define sec second
template <class T>
inline void cmax(T& x, const T& y) {
(x < y) && (x = y);
}
template <class T>
inline void cmin(T& x, const T& y) {
(x > y) && (x = y);
}
const int qwq = 1e7;
int phi[qwq + 10];
int qpow(int x, int y, int p) {
int ans = 1;
for (; y; y >>= 1, x = 1ll * x * x % p)
if (y & 1) ans = 1ll * ans * x % p;
return ans;
}
int solve(int p) { return (p == 1) ? 0 : qpow(2, solve(phi[p]) + phi[p], p); }
signed main() {
#ifdef _WIN64
freopen("testdata.in", "r", stdin);
#endif
for (int i = 2; i <= qwq; i++) {
if (phi[i]) continue;
for (int j = i; j <= qwq; j += i) {
if (!phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
int T;
in >> T;
while (T--) {
int p;
in >> p;
out << solve(p) << '\n';
}
return out.flush(), 0;
}
给定 \(a \{ \}\) 让你求 \(a_l ^ {a_{l+1} ^ {…^{a_r}}}\)
然后你会发现 \(\varphi(x)\) 在log层的时候会变成 1 ,所以暴力递归就好了,如果觉得慢,可以给 \(\varphi\) 加个记忆化。
// by Isaunoya
#include <bits/stdc++.h>
using namespace std;
#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
#define int long long
const int _ = 1 << 21;
struct I {
char fin[_], *p1 = fin, *p2 = fin;
inline char gc() {
return (p1 == p2) && (p2 = (p1 = fin) + fread(fin, 1, _, stdin), p1 == p2) ? EOF : *p1++;
}
inline I& operator>>(int& x) {
bool sign = 1;
char c = 0;
while (c < 48) ((c = gc()) == 45) && (sign = 0);
x = (c & 15);
while ((c = gc()) > 47) x = (x << 1) + (x << 3) + (c & 15);
x = sign ? x : -x;
return *this;
}
inline I& operator>>(double& x) {
bool sign = 1;
char c = 0;
while (c < 48) ((c = gc()) == 45) && (sign = 0);
x = (c - 48);
while ((c = gc()) > 47) x = x * 10 + (c - 48);
if (c == '.') {
double d = 1.0;
while ((c = gc()) > 47) d = d * 0.1, x = x + (d * (c - 48));
}
x = sign ? x : -x;
return *this;
}
inline I& operator>>(char& x) {
do
x = gc();
while (isspace(x));
return *this;
}
inline I& operator>>(string& s) {
s = "";
char c = gc();
while (isspace(c)) c = gc();
while (!isspace(c) && c != EOF) s += c, c = gc();
return *this;
}
} in;
struct O {
char st[100], fout[_];
signed stk = 0, top = 0;
inline void flush() { fwrite(fout, 1, top, stdout), fflush(stdout), top = 0; }
inline O& operator<<(int x) {
if (top > (1 << 20)) flush();
if (x < 0) fout[top++] = 45, x = -x;
do
st[++stk] = x % 10 ^ 48, x /= 10;
while (x);
while (stk) fout[top++] = st[stk--];
return *this;
}
inline O& operator<<(char x) {
fout[top++] = x;
return *this;
}
inline O& operator<<(string s) {
if (top > (1 << 20)) flush();
for (char x : s) fout[top++] = x;
return *this;
}
} out;
#define pb emplace_back
#define fir first
#define sec second
template <class T>
inline void cmax(T& x, const T& y) {
(x < y) && (x = y);
}
template <class T>
inline void cmin(T& x, const T& y) {
(x > y) && (x = y);
}
int n, m, q;
vector<int> a;
map<int, int> phi;
int getphi(int x) {
if (phi.count(x)) return phi[x];
int res = x, qwq = x;
for (int i = 2; i <= sqrt(x); ++i)
if (!(x % i)) {
res = res / i * (i - 1);
while (!(x % i)) x /= i;
}
if (x > 1) res = res / x * (x - 1);
return phi[qwq] = res;
}
int mod(int x, int p) { return (x < p) ? x : (x % p + p); }
int qpow(int x, int y, int p) {
int ans = 1;
for (; y; y >>= 1, x = mod(x * x, p))
if (y & 1) ans = mod(ans * x, p);
return ans;
}
int dfs(int l, int r, int p) {
if (l == r || p == 1) return mod(a[l], p);
return qpow(a[l], dfs(l + 1, r, getphi(p)), p);
}
signed main() {
#ifdef _WIN64
freopen("testdata.in", "r", stdin);
#endif
in >> n >> m;
a.resize(n);
for (int i = 0; i < n; i++) in >> a[i];
in >> q;
while (q--) {
int l, r;
in >> l >> r;
--l, --r;
out << dfs(l, r, m) % m << '\n';
}
return out.flush(), 0;
}