cp-library

競技プログラミング用 C++ ライブラリ

View the Project on GitHub qandori/cp-library

:warning: 剰余累乗・逆元

math/modular_arithmetic.hpp · GitHub で見る

共通ページ

#include "lib/math/modular_arithmetic.hpp"
#include <cassert>

int main() {
	assert(pow_mod(-2, 10, 1000) == 24);
	assert(inv_mod(3, 10) == 7);
}
関数 引数・返り値
pow_mod(x, n, m) x, n は std::int64_t、m は std::uint32_t。n >= 0, m >= 1 で \(x^n\bmod m\) を std::uint32_t で返す
inv_mod(x, m) 両引数は std::int64_t、m >= 1。\(xy\equiv1\pmod m\) を満たす 0 <= y < m を std::int64_t で返す

どちらも素数・合成数の法と負の x に対応します。法 1 の返り値は 0 です。0 の 0 乗は 1 を法で正規化した値です。不正な法・負の指数は std::invalid_argument、逆元が存在しない場合は std::domain_error です。inv_mod は定数式でも利用できます。

pow_mod は \(O(\log n)\) 時間、inv_mod は \(O(\log m)\) 時間、追加空間はいずれも \(O(1)\) です。指数 0 は定数時間です。

依存ライブラリ

コード

#ifndef MODULAR_ARITHMETIC_HPP
#define MODULAR_ARITHMETIC_HPP

#include "linear_congruence.hpp"
#include "../components/barrett32.hpp"
#include <stdexcept>

inline std::uint32_t pow_mod(std::int64_t x, std::int64_t n, std::uint32_t m) {
	if (!m || n < 0) throw std::invalid_argument("pow_mod arguments");
	std::int64_t r = x % std::int64_t(m);
	if (r < 0) r += m;
	return Barrett32(m).pow(std::uint32_t(r), std::uint64_t(n));
}

constexpr std::int64_t inv_mod(std::int64_t x, std::int64_t m) {
	auto result = linear_congruence(x, 1, m);
	if (!result) throw std::domain_error("inverse does not exist");
	return result->residue;
}

#endif
Back to top page