結果

問題 No.181 A↑↑N mod M
ユーザー anqooqieanqooqie
提出日時 2021-07-24 03:38:35
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 2 ms / 5,000 ms
コード長 17,706 bytes
コンパイル時間 2,781 ms
コンパイル使用メモリ 225,420 KB
実行使用メモリ 4,384 KB
最終ジャッジ日時 2023-09-26 09:15:27
合計ジャッジ時間 5,269 ms
ジャッジサーバーID
(参考情報)
judge14 / judge13
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,380 KB
testcase_01 AC 2 ms
4,380 KB
testcase_02 AC 1 ms
4,380 KB
testcase_03 AC 2 ms
4,380 KB
testcase_04 AC 2 ms
4,384 KB
testcase_05 AC 2 ms
4,380 KB
testcase_06 AC 1 ms
4,384 KB
testcase_07 AC 2 ms
4,384 KB
testcase_08 AC 1 ms
4,384 KB
testcase_09 AC 1 ms
4,380 KB
testcase_10 AC 1 ms
4,384 KB
testcase_11 AC 1 ms
4,380 KB
testcase_12 AC 2 ms
4,384 KB
testcase_13 AC 2 ms
4,384 KB
testcase_14 AC 1 ms
4,380 KB
testcase_15 AC 2 ms
4,384 KB
testcase_16 AC 2 ms
4,380 KB
testcase_17 AC 2 ms
4,384 KB
testcase_18 AC 2 ms
4,384 KB
testcase_19 AC 2 ms
4,380 KB
testcase_20 AC 1 ms
4,380 KB
testcase_21 AC 1 ms
4,384 KB
testcase_22 AC 2 ms
4,380 KB
testcase_23 AC 2 ms
4,380 KB
testcase_24 AC 2 ms
4,380 KB
testcase_25 AC 1 ms
4,384 KB
testcase_26 AC 2 ms
4,380 KB
testcase_27 AC 1 ms
4,384 KB
testcase_28 AC 2 ms
4,380 KB
testcase_29 AC 1 ms
4,380 KB
testcase_30 AC 1 ms
4,384 KB
testcase_31 AC 1 ms
4,380 KB
testcase_32 AC 1 ms
4,384 KB
testcase_33 AC 2 ms
4,380 KB
testcase_34 AC 1 ms
4,384 KB
testcase_35 AC 2 ms
4,380 KB
testcase_36 AC 1 ms
4,380 KB
testcase_37 AC 2 ms
4,380 KB
testcase_38 AC 1 ms
4,380 KB
testcase_39 AC 1 ms
4,384 KB
testcase_40 AC 1 ms
4,380 KB
testcase_41 AC 1 ms
4,380 KB
testcase_42 AC 1 ms
4,384 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#line 1 "/home/anqooqie/.proconlib/tools/util.hpp"



// To see the details of my library, visit my GitHub Pages.
// https://anqooqie.github.io/proconlib/

#ifdef LOCAL
  #ifndef _GLIBCXX_DEBUG
    #define _GLIBCXX_DEBUG
  #endif
#else
  #ifndef NDEBUG
    #define NDEBUG
  #endif
#endif

#include <bits/stdc++.h>
#line 1 "/home/anqooqie/.proconlib/tools/resize.hpp"



#line 5 "/home/anqooqie/.proconlib/tools/resize.hpp"

// Source: https://koyumeishi.hatenablog.com/entry/2016/02/01/152426
// License: unknown
// Author: koyumeishi

namespace tools {
  template <class T, class Allocator, typename Head>
  void resize(::std::vector<T, Allocator>& vector, const Head& head) {
    vector.resize(head);
  }
  template <class T, class Allocator, typename Head, typename... Tail>
  void resize(::std::vector<T, Allocator>& vector, const Head& head, const Tail&... tail) {
    vector.resize(head);
    for (auto& child : vector) {
      ::tools::resize(child, tail...);
    }
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/fill.hpp"



#line 5 "/home/anqooqie/.proconlib/tools/fill.hpp"
#include <type_traits>
#line 1 "/home/anqooqie/.proconlib/tools/is_range.hpp"



#line 7 "/home/anqooqie/.proconlib/tools/is_range.hpp"

namespace tools {
  template <typename T>
  class is_range {
  private:
    template <typename U>
    static auto check(U x) -> decltype(::std::begin(x), ::std::end(x), ::std::true_type{});
    static ::std::false_type check(...);

  public:
    static const bool value = decltype(check(::std::declval<T>()))::value;
  };
}


#line 9 "/home/anqooqie/.proconlib/tools/fill.hpp"

namespace tools {
  template <class T, class Allocator, typename V>
  auto fill(::std::vector<T, Allocator>& vector, const V& value) -> ::std::enable_if_t<!::tools::is_range<T>::value, void> {
    ::std::fill(::std::begin(vector), ::std::end(vector), value);
  }
  template <class T, class Allocator, typename V>
  auto fill(::std::vector<T, Allocator>& vector, const V& value) -> ::std::enable_if_t<::tools::is_range<T>::value, void> {
    for (auto& child : vector) {
      ::tools::fill(child, value);
    }
  }
}


#line 20 "/home/anqooqie/.proconlib/tools/util.hpp"

using i64 = ::std::int_fast64_t;
using u64 = ::std::uint_fast64_t;
using i32 = ::std::int_fast32_t;
using u32 = ::std::uint_fast32_t;

#define ALL(x) ::std::begin((x)), ::std::end((x))

namespace tools {
  namespace detail {
    namespace util {
      template <typename T>
      class has_val {
      private:
        template <typename U>
        static auto check(U x) -> decltype(x.val(), ::std::true_type{});
        static ::std::false_type check(...);

      public:
        static const bool value = decltype(check(::std::declval<T>()))::value;
      };

      template <typename T>
      ::std::istream& read(::std::istream& is, T& container) {
        for (auto& v : container) {
          is >> v;
        }
        return is;
      }

      template <typename T>
      ::std::ostream& debug_print(::std::ostream& os, const T& container) {
        ::std::string delimiter = "";
        os << '[';
        for (const auto& v : container) {
          os << delimiter << v;
          delimiter = ", ";
        }
        os << ']';
        return os;
      }
    }
  }
}

template <class T, class Allocator>
::std::istream& operator>>(::std::istream& is, ::std::vector<T, Allocator>& vector) {
  return ::tools::detail::util::read(is, vector);
}
template <class T, ::std::size_t N>
::std::istream& operator>>(::std::istream& is, ::std::array<T, N>& array) {
  return ::tools::detail::util::read(is, array);
}
template <class T, class Allocator>
::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T, Allocator>& vector) {
  return ::tools::detail::util::debug_print(os, vector);
}
template <class T, ::std::size_t N>
::std::ostream& operator<<(::std::ostream& os, const ::std::array<T, N>& array) {
  return ::tools::detail::util::debug_print(os, array);
}
template <class Key, class Hash, class Pred, class Allocator>
::std::ostream& operator<<(::std::ostream& os, const ::std::unordered_set<Key, Hash, Pred, Allocator>& unordered_set) {
  return ::tools::detail::util::debug_print(os, unordered_set);
}

template <class T, class Container>
::std::ostream& operator<<(::std::ostream& os, ::std::stack<T, Container>& stack) {
  ::std::stack<T, Container> other;
  ::std::string delimiter = "";
  os << '[';
  while (!stack.empty()) {
    os << delimiter << stack.top();
    delimiter = ", ";
    other.push(stack.top());
    stack.pop();
  }
  os << ']';

  while (!other.empty()) {
    stack.push(other.top());
    other.pop();
  }

  return os;
}

template <class T, class Container>
::std::ostream& operator<<(::std::ostream& os, ::std::queue<T, Container>& queue) {
  ::std::queue<T, Container> other = queue;
  ::std::string delimiter = "";
  os << '[';
  while (!queue.empty()) {
    os << delimiter << queue.front();
    delimiter = ", ";
    queue.pop();
  }
  os << ']';

  queue = ::std::move(other);
  return os;
}

template <class T1, class T2>
::std::ostream& operator<<(::std::ostream& os, const ::std::pair<T1, T2>& pair) {
  return os << '[' << pair.first << ", " << pair.second << ']';
}
template <int I = -1, typename... Args>
::std::ostream& operator<<(::std::ostream& os, const ::std::tuple<Args...>& tuple) {
  if constexpr (I == -1) {
    os << '[';
  } else if constexpr (I == int(sizeof...(Args))) {
    os << ']';
  } else if constexpr (I == 0) {
    os << ::std::get<I>(tuple);
  } else {
    os << ", " << ::std::get<I>(tuple);
  }

  if constexpr (I < int(sizeof...(Args))) {
    return operator<<<I + 1>(os, tuple);
  } else {
    return os;
  }
}

template <typename T>
auto operator<<(::std::ostream& os, const T& x) -> ::std::enable_if_t<::tools::detail::util::has_val<T>::value, ::std::ostream&> {
  return os << x.val();
}


#line 1 "/home/anqooqie/.proconlib/tools/tetration_mod.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/pow.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/monoid.hpp"



#line 7 "/home/anqooqie/.proconlib/tools/monoid.hpp"

namespace tools {
  namespace monoid {
    template <typename Type, Type E = ::std::numeric_limits<Type>::min()>
    struct max {
      using T = Type;
      static T op(const T lhs, const T rhs) {
        return ::std::max(lhs, rhs);
      }
      static T e() {
        return E;
      }
    };

    template <typename Type, Type E = ::std::numeric_limits<Type>::max()>
    struct min {
      using T = Type;
      static T op(const T lhs, const T rhs) {
        return ::std::min(lhs, rhs);
      }
      static T e() {
        return E;
      }
    };

    template <typename Type>
    struct multiplies {
      using T = Type;
      static T op(const T lhs, const T rhs) {
        return lhs * rhs;
      }
      static T e() {
        return T(1);
      }
    };

    template <typename Type>
    struct gcd {
      using T = Type;
      static T op(const T lhs, const T rhs) {
        return ::std::gcd(lhs, rhs);
      }
      static T e() {
        return T(0);
      }
    };

    template <typename Type, Type E>
    struct update {
      using T = Type;
      static T op(const T lhs, const T rhs) {
        return lhs == E ? rhs : lhs;
      }
      static T e() {
        return E;
      }
    };
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/square.hpp"



#line 5 "/home/anqooqie/.proconlib/tools/square.hpp"

namespace tools {

  template <typename M>
  typename M::T square(const typename M::T& x) {
    return M::op(x, x);
  }

  template <typename T>
  T square(const T& x) {
    return ::tools::square<::tools::monoid::multiplies<T>>(x);
  }
}


#line 7 "/home/anqooqie/.proconlib/tools/pow.hpp"

namespace tools {

  template <typename M>
  typename M::T pow(const typename M::T& base, const ::std::size_t& exponent) {
    return exponent == 0
      ? M::e()
      : exponent % 2 == 0
        ? ::tools::square<M>(::tools::pow<M>(base, exponent / 2))
        : M::op(::tools::pow<M>(base, exponent - 1), base);
  }

  template <typename T>
  T pow(const T& base, const ::std::size_t& exponent) {
    return ::tools::pow<::tools::monoid::multiplies<T>>(base, exponent);
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/prime_factorization.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/is_prime.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/prod_mod.hpp"



namespace tools {

  template <typename T1, typename T2, typename T3>
  constexpr T3 prod_mod(const T1 x, const T2 y, const T3 m) {
    using u128 = unsigned __int128;
    u128 prod_mod = u128(x >= 0 ? x : -x) * u128(y >= 0 ? y : -y) % u128(m);
    if (((x >= 0) ^ (y >= 0)) == 1) prod_mod = u128(m) - prod_mod;
    return prod_mod;
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/pow_mod.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/mod.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/quo.hpp"



#line 5 "/home/anqooqie/.proconlib/tools/quo.hpp"

namespace tools {

  template <typename M, typename N>
  constexpr ::std::common_type_t<M, N> quo(const M lhs, const N rhs) {
    if (lhs >= 0) {
      return lhs / rhs;
    } else {
      if (rhs >= 0) {
        return -((-lhs - 1 + rhs) / rhs);
      } else {
        return (-lhs - 1 + -rhs) / -rhs;
      }
    }
  }
}


#line 6 "/home/anqooqie/.proconlib/tools/mod.hpp"

namespace tools {

  template <typename M, typename N>
  constexpr ::std::common_type_t<M, N> mod(const M lhs, const N rhs) {
    if constexpr (::std::is_unsigned_v<M> && ::std::is_unsigned_v<N>) {
      return lhs % rhs;
    } else {
      return lhs - ::tools::quo(lhs, rhs) * rhs;
    }
  }
}


#line 6 "/home/anqooqie/.proconlib/tools/pow_mod.hpp"

namespace tools {

  template <typename T1, typename T2, typename T3>
  constexpr T3 pow_mod(const T1 x, T2 n, const T3 m) {
    if (m == 1) return 0;
    T3 r = 1;
    T3 y = ::tools::mod(x, m);
    while (n > 0) {
      if ((n & 1) > 0) {
        r = ::tools::prod_mod(r, y, m);
      }
      y = ::tools::prod_mod(y, y, m);
      n /= 2;
    }
    return r;
  }
}


#line 8 "/home/anqooqie/.proconlib/tools/is_prime.hpp"

namespace tools {

  constexpr bool is_prime(const ::std::uint_fast64_t n) {
    constexpr ::std::array<::std::uint_fast64_t, 7> bases = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};

    if (n <= 1) return false;
    if (n == 2) return true;
    if (n % 2 == 0) return false;

    ::std::uint_fast64_t d = n - 1;
    for (; d % 2 == 0; d /= 2);

    for (const ::std::uint_fast64_t a : bases) {
      if (a % n == 0) return true;

      ::std::uint_fast64_t power = d;
      ::std::uint_fast64_t target = ::tools::pow_mod(a, power, n);

      bool is_composite = true;
      if (target == 1) is_composite = false;
      for (; is_composite && power != n - 1; power *= 2, target = ::tools::prod_mod(target, target, n)) {
        if (target == n - 1) is_composite = false;
      }

      if (is_composite) {
        return false;
      }
    }

    return true;
  }
}


#line 12 "/home/anqooqie/.proconlib/tools/prime_factorization.hpp"

namespace tools {

  template <typename T>
  ::std::map<T, T> prime_factorization(T n) {
    assert(1 <= n && n <= 1000000000000000000);
    ::std::map<T, T> result;

    for (; n % 2 == 0; n /= 2) {
      ++result[2];
    }
    if (n == 1) return result;

    ::std::minstd_rand engine;
    ::std::queue<T> factors({n});
    while (!factors.empty()) {
      const T factor = factors.front();
      factors.pop();
      if (::tools::is_prime(factor)) {
        ++result[factor];
      } else {
        ::std::uniform_int_distribution<T> dist(1, factor - 2);
        while (true) {
          T c = dist(engine);
          if (c == factor - 2) c = factor - 1;
          T x = 2;
          T y = 2;
          T d = 1;
          while (d == 1) {
            x = ::tools::prod_mod(x, x, factor);
            x += c;
            if (x >= factor) x -= factor;
            y = ::tools::prod_mod(y, y, factor);
            y += c;
            if (y >= factor) y -= factor;
            y = ::tools::prod_mod(y, y, factor);
            y += c;
            if (y >= factor) y -= factor;
            d = ::std::gcd(::std::abs(x - y), factor);
          }
          if (d < factor) {
            factors.push(d);
            factors.push(factor / d);
            break;
          }
        }
      }
    }

    return result;
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/totient.hpp"



#line 7 "/home/anqooqie/.proconlib/tools/totient.hpp"

namespace tools {

  template <typename T>
  T totient(const T& x) {
    assert(1 <= x && x <= 1000000000000000000);
    T prod = 1;
    for (const auto& [distinct_prime_factor, exponent] : ::tools::prime_factorization(x)) {
      prod *= ::tools::pow(distinct_prime_factor, exponent - 1) * (distinct_prime_factor - 1);
    }
    return prod;
  }
}


#line 1 "/home/anqooqie/.proconlib/tools/garner.hpp"



#include <optional>
#line 1 "/home/anqooqie/.proconlib/tools/inv_mod.hpp"



#line 1 "/home/anqooqie/.proconlib/tools/extgcd.hpp"



#line 6 "/home/anqooqie/.proconlib/tools/extgcd.hpp"

namespace tools {

  template <typename T>
  ::std::tuple<T, T, T> extgcd(T prev_r, T r) {
    T prev_s = 1;
    T prev_t = 0;
    T s = 0;
    T t = 1;
    while (r != 0) {
      const T q = ::tools::quo(prev_r, r);
      const T next_r = prev_r - q * r;
      prev_r = r;
      r = next_r;
      const T next_s = prev_s - q * s;
      prev_s = s;
      s = next_s;
      const T next_t = prev_t - q * t;
      prev_t = t;
      t = next_t;
    }

    if (prev_r < T(0)) prev_r = -prev_r;
    return {prev_s, prev_t, prev_r};
  }
}


#line 7 "/home/anqooqie/.proconlib/tools/inv_mod.hpp"

namespace tools {

  template <typename T1, typename T2>
  constexpr T2 inv_mod(const T1 x, const T2 m) {
    const auto [x0, y0, gcd] = ::tools::extgcd(x, m);
    assert(gcd == 1);
    return ::tools::mod(x0, m);
  }
}


#line 13 "/home/anqooqie/.proconlib/tools/garner.hpp"

// Source: https://qiita.com/drken/items/ae02240cd1f8edfc86fd
// License: unknown
// Author: drken

namespace tools {

  template <typename Iterator, typename ModType>
  ::std::optional<::std::pair<::std::int_fast64_t, ::std::int_fast64_t>> garner(const Iterator& begin, const Iterator& end, const ModType& mod) {
    ::std::vector<::std::int_fast64_t> b, m;
    for (auto it = begin; it != end; ++it) {
      b.push_back(::tools::mod(it->first, it->second));
      m.push_back(it->second);
    }

    ::std::int_fast64_t lcm = 1;
    for (::std::size_t i = 0; i < b.size(); ++i) {
      for (::std::size_t j = 0; j < i; ++j) {
        ::std::int_fast64_t g = ::std::gcd(m[i], m[j]);

        if ((b[i] - b[j]) % g != 0) return ::std::nullopt;

        m[i] /= g;
        m[j] /= g;

        ::std::int_fast64_t gi = ::std::gcd(m[i], g), gj = g / gi;

        do {
          g = ::std::gcd(gi, gj);
          gi *= g, gj /= g;
        } while (g != 1);

        m[i] *= gi, m[j] *= gj;

        b[i] %= m[i], b[j] %= m[j];
      }
    }
    for (::std::size_t i = 0; i < b.size(); ++i) {
      (lcm *= m[i]) %= mod;
    }

    m.push_back(mod);
    ::std::vector<::std::int_fast64_t> coeffs(m.size(), 1);
    ::std::vector<::std::int_fast64_t> constants(m.size(), 0);
    for (::std::size_t k = 0; k < b.size(); ++k) {
      ::std::int_fast64_t t = ::tools::mod((b[k] - constants[k]) * ::tools::inv_mod(coeffs[k], m[k]), m[k]);
      for (::std::size_t i = k + 1; i < m.size(); ++i) {
        (constants[i] += t * coeffs[i]) %= m[i];
        (coeffs[i] *= m[k]) %= m[i];
      }
    }

    return ::std::make_optional<::std::pair<::std::int_fast64_t, ::std::int_fast64_t>>(constants.back(), lcm);
  }

  template <typename M, typename Iterator>
  ::std::optional<::std::pair<M, M>> garner(const Iterator& begin, const Iterator& end) {
    const auto result = ::tools::garner(begin, end, M::mod());
    if (!result) return ::std::nullopt;
    return ::std::make_optional<::std::pair<M, M>>(M::raw(result->first), M::raw(result->second));
  }
}


#line 13 "/home/anqooqie/.proconlib/tools/tetration_mod.hpp"

namespace tools {

  template <typename T>
  T tetration_mod(const T a, const T b, const T m) {
    assert(a >= 0);
    assert(b >= 0);
    assert(m >= 1);

    if (m == 1) return 0;

    // It returns min(fa^^fb, 2^63 - 1).
    const auto f = [](const ::std::int_fast64_t fa, const ::std::int_fast64_t fb) {
      if (fa == 0) return 1 - fb % 2;
      if (fa == 1) return ::std::int_fast64_t(1);
      if (fb == 0) return ::std::int_fast64_t(1);
      if (fb == 1) return fa;
      if (fb == 2 && fa <= 15) return ::tools::pow(fa, fa);
      if (fb == 3 && fa <= 3) return ::tools::pow(fa, ::tools::pow(fa, fa));
      if (fb == 4 && fa <= 2) return ::tools::pow(fa, ::tools::pow(fa, ::tools::pow(fa, fa)));

      // Too large
      return ::std::numeric_limits<::std::int_fast64_t>::max();
    };

    if (f(a, b) < ::std::numeric_limits<::std::int_fast64_t>::max()) {
      return f(a, b) % m;
    }

    ::std::vector<::std::pair<T, T>> answers;
    for (const auto& [p, q] : ::tools::prime_factorization(m)) {
      const T P = ::tools::pow(p, q);
      if (::std::gcd(a, p) == 1) {
        answers.emplace_back(::tools::pow_mod(a, ::tools::tetration_mod(a, b - 1, ::tools::totient(P)), P), P);
      } else {
        if (f(a, b - 1) >= q) {
          answers.emplace_back(0, P);
        } else {
          answers.emplace_back(::tools::pow_mod(a, f(a, b - 1), P), P);
        }
      }
    }

    return ::tools::garner(answers.begin(), answers.end(), m)->first;
  }
}


#line 3 "main.cpp"

int main() {
  std::cin.tie(nullptr);
  std::ios_base::sync_with_stdio(false);

  i64 A, N, M;
  std::cin >> A >> N >> M;
  std::cout << tools::tetration_mod(A, N, M) << '\n';
  return 0;
}
0