$\newcommand{\O}{\mathrm{O}}$
テトレーション $(a ↑↑ b) \% \ p$ を求めるアルゴリズム, つまり $a^{a^{a^{a^{\ldots}}}}$
($a$ が $b$ 個続く) の $\mathbb{Z} / p \mathbb{Z}$ 上での値を求めるアルゴリズムである.
ただしべき乗の演算は右結合的であることに注意.
(実装の都合上 $mod$ の値は $2^{31}$ 未満であることを仮定)
(関数)
tetration$(a, b, mod)$ : $(a ↑↑ b)\ \% mod$ を求める.
時間計算量: $\O (\sqrt{mod})$
unsigned int phi(unsigned int n) { unsigned int res = n; if(n % 2 == 0){ res = res / 2; do{ n /= 2; }while(n % 2 == 0); } if(n % 3 == 0){ res = res / 3 * 2; do{ n /= 3; }while(n % 3 == 0); } for(unsigned int i = 5; i * i <= n; i += 4){ if(n % i == 0){ res = res / i * (i - 1); do{ n /= i; }while(n % i == 0); } i += 2; if(n % i == 0){ res = res / i * (i - 1); do{ n /= i; }while(n % i == 0); } } if(n != 1) res = res / n * (n - 1); return res; } unsigned int mod_pow(unsigned long long a, unsigned int b, unsigned int mod, bool flag) { unsigned long long res = 1; while(b){ if(b & 1){ // Note: condition is true if a >= mod and flag = false if((res *= a) >= mod) res %= mod, flag = true; } if((a *= a) >= mod) a = a % mod + mod; b >>= 1; } return res + (flag ? mod : 0); } unsigned int rec(unsigned int a, unsigned int b, unsigned int mod) { if(b == 2) return mod_pow(a, a, mod, false); const unsigned int phi_val = phi(mod); const unsigned int res = ((phi_val == 1) ? 1 : rec(a, b - 1, phi_val)); return mod_pow(a, res, mod, (res >= phi_val)); } unsigned int tetration(unsigned int a, unsigned int b, unsigned int mod) { if(mod == 1) return 0; if(a == 0) return !(b & 1); if(a == 1 || b == 0) return 1; if(b == 1) return (a >= mod) ? (a % mod) : a; const unsigned int res = rec(a, b, mod); return (res >= mod) ? (res - mod) : res; }
Atcoder : 冪冪ゲーム (Powerful Fever!)
提出コード
yosupo さんの library checker : Tetration Mod
提出コード