Skip to Content
Team NoteAlgorithmBerlekamp-Kitamasa

Berlekamp-Kitamasa

const int mod = 1e9 + 7; inline int md(int x) { return md(mod, x); } inline ll poww(ll a, ll b) { ll ret = 1; while (b) { if (b & 1) { ret *= a; ret %= mod; } a *= a; if (~mod) a %= mod; b >>= 1; } return ret; } vi berlekamp_massey(vi x) { vi ls, cur; int lf, ld; for (int i = 0; i < sz(x); i++) { int t = 0; for (int j = 0; j < sz(cur); j++) { t = md(t + 1ll * x[i - j - 1] * cur[j]); } if (md(t - x[i]) == 0) continue; if (!sz(cur)) { cur.resize(i + 1); lf = i; ld = md(t - x[i]); continue; } int k = md(-(x[i] - t) * poww(ld, mod - 2)); vi c(i - lf - 1); c.pb(k); for (auto &j: ls) c.pb(md(-j * k)); if (sz(c) < sz(cur)) c.resize(sz(cur)); for (int j = 0; j < sz(cur); j++) { c[j] = md(c[j] + cur[j]); } if (i - lf + sz(ls) >= sz(cur)) { tie(ls, lf, ld) = make_tuple(cur, i, md(t - x[i])); } cur = c; } for (auto &i: cur) i = md(i); reverse(all(cur)); return cur; } vi mul(const vi &a, const vi &b) { int n = sz(a), m = sz(b); vi ret(n + m - 1); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) ret[i + j] = md(ret[i + j] + a[i] * b[j]); return ret; } vi div(const vi &a, const vi &b) { int n = sz(a), m = sz(b); vi ret(a); for (int i = n - 1; i >= m - 1; i--) for (int j = 0; j < m; j++) ret[i + j - m + 1] = md(ret[i + j - m + 1] - ret[i] * b[j]); ret.resize(m - 1); return ret; } int kitamasa(int n, const vi &c, const vi &a) { if (n < sz(a)) return md(a[n]); vi cur{1}, m = c, x = {0, 1}; for (int &i: m) i *= -1; m.pb(1); while (n) { if (n & 1) cur = div(mul(cur, x), m); x = div(mul(x, x), m); n >>= 1; } int ret = 0; for (int i = 0; i < sz(c); i++) ret = md(ret + cur[i] * a[i]); return ret; } int guess(int n, const vi &dp) { if (n < sz(dp)) return md(dp[n]); vi rec = berlekamp_massey(dp); if (!sz(rec)) return -1; return kitamasa(n, rec, dp); }
Last updated on