テトレーション $(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
提出コード