cp-library

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

View the Project on GitHub qandori/cp-library

:heavy_check_mark: 多項式の積・打ち切り積の共通処理

components/polynomial_multiply.hpp · GitHub で見る

共通ページ

polynomial_detail::Products<F,Limit> は、積の木と FPS 合成が共有する内部部品です。F は F::multiply を持つ多項式型、Limit はその畳み込みの最大係数数です。

multiply(a,b) は通常の積、multiply_low(a,b,n) は積の低次 n 係数を返します。後者の返り値は長さ n で、不足分は 0 です。積が Limit を超える場合は係数列を分割して計算します。

分割しない場合の時間は F::multiply と同じです。分割する場合は、必要なブロック対ごとの畳み込み時間の合計と、係数の加算時間がかかります。追加空間は出力と各ブロックの作業領域に比例します。

検証コード

コード

#ifndef CP_COMPONENTS_POLYNOMIAL_MULTIPLY_HPP
#define CP_COMPONENTS_POLYNOMIAL_MULTIPLY_HPP

#include <algorithm>
#include <cstddef>

namespace polynomial_detail {
template<class F, std::size_t Limit = 1U << 23>
struct Products {
	static_assert(Limit >= 2);
	static F multiply(const F& a, const F& b) {
		if (a.empty() || b.empty()) return {};
		const auto n = a.size() + b.size() - 1;
		return n <= Limit ? F::multiply(a, b) : multiply_low(a, b, n);
	}
	static F multiply_low(const F& a, const F& b, std::size_t n) {
		F result(n);
		constexpr std::size_t block = Limit / 2;
		for (std::size_t i = 0; i < std::min(a.size(), n); i += block)
			for (std::size_t j = 0; j < std::min(b.size(), n - i); j += block) {
				F x(a.begin() + i, a.begin() + std::min(i + block, a.size()));
				F y(b.begin() + j, b.begin() + std::min(j + block, b.size()));
				F p = F::multiply(x, y);
				for (std::size_t k = 0; k < std::min(p.size(), n - i - j); ++k)
					result[i + j + k] += p[k];
			}
		return result;
	}
};
}

#endif
Back to top page