1. 程式人生 > >Berlekamp-Massey演算法學習筆記

Berlekamp-Massey演算法學習筆記

Berlekamp-Massey演算法

很久之前就聽說過這個演算法,當時六校聯考的時候Day1T1是一道很有意思的遞推,神仙zzx不會做於是就拿BM演算法艹出了遞推式Orzzzzzzzzzzx

推薦一篇講的詳細的不能再詳細的部落格

我就不詳細說了,只記一下自己感覺比較難理解的地方

\(r(m)\)表示序列的遞推式且長度為\(m\)

\(f(r, i)\)表示\(\sum_{j = 1}^m r_j * a[i - j]\)

\(\delta(r, i)\)表示\(a[i] - f(r, i)\)

\(fail_i\)表示第\(i\)個遞推式出錯的位置

對於某一個位置\(i\)

,如果我們求出的\(\delta(r, i) \not = 0\),這時候我們需要構造一個遞推式\(r'(m')\),滿足\(\forall j \in [m' + 1, i - 1] f(r', j) = 0\)\(f(r, i) = \delta(r, i)\)

這樣我們令\(r = r + r'\)就得到新位置的遞推式了

\(r'\)可以這麼構造

\(mul = \frac{\delta(r, i)}{\delta(r, fail_{cnt - 1})}\)

那麼\(r' = \{0, 0, 0 \dots, 0, mul, -mul * R_{cnt - 1} \}\)

\(0\)的個數為\(i - fail_{cnt - 1} - 1\)

至於為什麼這麼構造是對的,我思考了挺長時間,簡單的證明一下

首先對於\(\forall j \in [m' + 1, i - 1]\), \(\delta(r', j) = 0\)

仔細想了想,,發現自己並不會證。。如果哪位大佬會的話可以教教本蒟蒻

感性理解就是因為\(r\)\([1, M]\)處滿足任意位置為\(0\),然後右移一下還滿足?。。

至於為什麼\(f(r', i) = \delta(r, i)\)

可以這麼考慮,前\(i - fail_{cnt - 1} - 1\)個位置產生的貢獻為\(0\)

\(mul\)產生的貢獻為\(mul * a_{fail_{cnt - 1}}\)

\(-mul * R_{cnt - 1}\)產生的貢獻為\(-mul * (a[fail_{cnt - 1}] - \delta(r, fail_{cnt - 1]})\)

合併同類項後可以得到\(mul * \delta(r, fail_{cnt - 1}) = \delta(r, i)\)

程式碼如下

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2005;
const double eps = 1e-8;
int cnt, fail[MAXN];
double val[MAXN], delta[MAXN];
vector <double> ans[MAXN];
int main() {
    int N; scanf("%d", &N);
    for (int i = 1; i <= N; i++) scanf("%lf", &val[i]);
    for (int i = 1; i <= N; i++) {
        double tmp = val[i];
        for (int j = 0; j < ans[cnt].size(); j++)
            tmp -= ans[cnt][j] * val[i - j - 1];
        delta[i] = tmp;
        if (fabs(tmp) <= eps) continue;
        fail[cnt] = i;
        if (cnt == 0) {
            ans[++cnt].resize(i);
            continue;
        }
        double mul = delta[i] / delta[fail[cnt - 1]];
        cnt++; ans[cnt].resize(i - fail[cnt - 2] - 1);
        ans[cnt].push_back(mul);
        for (int j = 0; j < ans[cnt - 2].size(); j++)
            ans[cnt].push_back(ans[cnt - 2][j] * -mul);
        if (ans[cnt].size() < ans[cnt - 1].size()) ans[cnt].resize(ans[cnt - 1].size());
        for (int j = 0; j < ans[cnt - 1].size(); j++)
            ans[cnt][j] += ans[cnt - 1][j];
    }
    for (int i = 0; i < ans[cnt].size(); i++)
        cout << ans[cnt][i] << ' ';
    return 0;
}