扩展欧拉定理 [学习笔记]

咕了好久…

P4139 上帝与集合的正确用法

对于 \(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;
}

CF906D Power Tower

给定 \(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;
}
posted @ 2020-03-10 18:00  _Isaunoya  阅读(148)  评论(0编辑  收藏  举报