BZOJ3884上帝与集合的正确用法

时间:2022-03-10 11:59:29

题目链接

BZOJ

洛谷

解析

欧拉定理及扩展欧拉定理:
\[ a^b \equiv \begin{cases} a^{b \ mod \ \phi(p)}, & \gcd (a, p) = 1 \\ a^b, & \gcd(a, p) \ne 1, &b < \phi(p) \\ a^{b \ mod \ \phi(p) + \phi(p)}, & \gcd(a, p) \ne 1, & b \ge \phi(p) \end{cases} \ (mod \ p) \]
然后其实可以把第一个和第三个合起来得到\(a^b \equiv a^{b \ mod \ \phi(p) + \phi(p)} (mod \ p),b \ge \phi(p)\)

令题目要求的\(2^{2^{2^{2^{..}}}}mod \ p\)\(f(p)\),那么\(f(p) = 2^{f(\phi(p)) + \phi(p)} (mod \ p)\)

于是线性筛出\(\phi\),递归地求\(f\)即可,边界条件是\(f(1) = 0\)

代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define MAXP 10000005

typedef long long LL;
int phi[MAXP], T, P;

void make_phi();
int calc(int);
int main() {
    make_phi();
    std::ios::sync_with_stdio(false);
    std::cin >> T;
    while (T--) {
        std::cin >> P;
        std::cout << calc(P) << std::endl;
    }
    return 0;
}
void make_phi() {
    static char isn_prime[MAXP];
    static std::vector<int> prime;
    phi[1] = 1;
    for (int i = 2; i <= MAXP; ++i) {
        if (!isn_prime[i]) {
            prime.push_back(i);
            phi[i] = i - 1;
        }
        for (int j = 0; j < prime.size() && (LL)i * prime[j] <= MAXP; ++j) {
            isn_prime[i * prime[j]] = 1;
            if (i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
            else { phi[i * prime[j]] = phi[i] * prime[j]; break; }
        }
    }
}
int qpower(int x, int y, int p) {
    int res = 1;
    while (y) {
        if (y & 1) res = (LL)res * x % p;
        x = (LL)x * x % p;
        y >>= 1;
    }
    return res;
}
int calc(int p) {
    if (p == 1) return 0;
    return qpower(2, calc(phi[p]) + phi[p], p);
}
//Rhein_E