cp-library-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub suisen-cp/cp-library-cpp

:heavy_check_mark: Berlekamp Massey (線形回帰数列の係数計算)
(library/polynomial/berlekamp_massey.hpp)

Berlekamp Massey (線形回帰数列の係数の計算)

体 $F$ 上の数列 $s=(s_0,s_1,\ldots,s_{n-1})$ に対して、

\[s_i=\sum_{j=1}^L c_j\cdot s_{i-j}\quad (\forall i\geq L)\]

を満たす数列 $c=(c_1,\ldots,c_L)$ のうち長さ $L$ が最小のものを $\Theta(n ^ 2)$ 時間で計算する。

Reference

[1] J. Massey, “Shift-register synthesis and BCH decoding,” in IEEE Transactions on Information Theory, vol. 15, no. 1, pp. 122-127, January 1969, doi: 10.1109/TIT.1969.1054260.

Verified with

Code

#ifndef SUISEN_BERLEKAMP_MASSEY
#define SUISEN_BERLEKAMP_MASSEY

#include <cassert>
#include <vector>

namespace suisen {
    /**
     * @brief Find linear recurrence in O(|s|^2) time
     * @tparam F Arbitrary field (operator +, -, *, /, +=, -=, *=, /= must be defined)
     * @param s Prefix of a linearly reccurent sequence
     * @return The vector of length L+1 c s.t. c_0=1 and s_i=Sum[j=1,L]c_i*s_{i-j} for all i>=L, where L is the minimum integer s.t. there exists such c of length L+1.
     */
    template <typename F>
    std::vector<F> find_linear_recuurence(const std::vector<F>& s) {
        std::vector<F> B{ 1 }, C{ 1 };
        B.reserve(s.size()), C.reserve(s.size());
        F b = 1;
        std::size_t L = 0;
        for (std::size_t N = 0, x = 1; N < s.size(); ++N) {
            F d = s[N];
            for (std::size_t i = 1; i <= L; ++i) d += C[i] * s[N - i];
            if (d == 0) {
                ++x;
            } else {
                F c = d / b;
                if (C.size() < B.size() + x) C.resize(B.size() + x);
                if (2 * L > N) {
                    for (std::size_t i = 0; i < B.size(); ++i) C[x + i] -= c * B[i];
                    ++x;
                } else {
                    std::vector<F> T = C;
                    for (std::size_t i = 0; i < B.size(); ++i) C[x + i] -= c * B[i];
                    L = N + 1 - L, B = std::move(T), b = d, x = 1;
                }
            }
        }
        C.resize(L + 1);
        for (std::size_t N = 1; N <= L; ++N) C[N] = -C[N];
        return C;
    }
} // namespace suisen


#endif // SUISEN_BERLEKAMP_MASSEY
#line 1 "library/polynomial/berlekamp_massey.hpp"



#include <cassert>
#include <vector>

namespace suisen {
    /**
     * @brief Find linear recurrence in O(|s|^2) time
     * @tparam F Arbitrary field (operator +, -, *, /, +=, -=, *=, /= must be defined)
     * @param s Prefix of a linearly reccurent sequence
     * @return The vector of length L+1 c s.t. c_0=1 and s_i=Sum[j=1,L]c_i*s_{i-j} for all i>=L, where L is the minimum integer s.t. there exists such c of length L+1.
     */
    template <typename F>
    std::vector<F> find_linear_recuurence(const std::vector<F>& s) {
        std::vector<F> B{ 1 }, C{ 1 };
        B.reserve(s.size()), C.reserve(s.size());
        F b = 1;
        std::size_t L = 0;
        for (std::size_t N = 0, x = 1; N < s.size(); ++N) {
            F d = s[N];
            for (std::size_t i = 1; i <= L; ++i) d += C[i] * s[N - i];
            if (d == 0) {
                ++x;
            } else {
                F c = d / b;
                if (C.size() < B.size() + x) C.resize(B.size() + x);
                if (2 * L > N) {
                    for (std::size_t i = 0; i < B.size(); ++i) C[x + i] -= c * B[i];
                    ++x;
                } else {
                    std::vector<F> T = C;
                    for (std::size_t i = 0; i < B.size(); ++i) C[x + i] -= c * B[i];
                    L = N + 1 - L, B = std::move(T), b = d, x = 1;
                }
            }
        }
        C.resize(L + 1);
        for (std::size_t N = 1; N <= L; ++N) C[N] = -C[N];
        return C;
    }
} // namespace suisen
Back to top page