很久之前就聽說過這個演算法,當時六校聯考的時候day1t1是一道很有意思的遞推,神仙zzx不會做於是就拿bm演算法艹出了遞推式orzzzzzzzzzzx
推薦一篇講的詳細的不能再詳細的部落格
我就不詳細說了,只記一下自己感覺比較難理解的地方
設\(r(m)\)表示序列的遞推式且長度為\(m\)
\(f(r, i)\)表示\(\sum_^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)}\)
那麼\(r' = \ \}\)
\(0\)的個數為\(i - fail_ - 1\)
至於為什麼這麼構造是對的,我思考了挺長時間,簡單的證明一下
首先對於\(\forall j \in [m' + 1, i - 1]\), \(\delta(r', j) = 0\)
仔細想了想,,發現自己並不會證。。如果哪位大佬會的話可以教教本蒟蒻
感性理解就是因為\(r\)在\([1, m]\)處滿足任意位置為\(0\),然後右移一下還滿足?。。
至於為什麼\(f(r', i) = \delta(r, i)\)
可以這麼考慮,前\(i - fail_ - 1\)個位置產生的貢獻為\(0\)
\(mul\)產生的貢獻為\(mul * a_}\)
\(-mul * r_\)產生的貢獻為\(-mul * (a[fail_] - \delta(r, fail_)\)
合併同類項後可以得到\(mul * \delta(r, fail_) = \delta(r, i)\)
**如下
#includeusing namespace std;
const int maxn = 2005;
const double eps = 1e-8;
int cnt, fail[maxn];
double val[maxn], delta[maxn];
vector ans[maxn];
int main()
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;
}
Berlekamp Massey演算法學習筆記
宣告 博主已退役,這是以前的總結,如有錯誤望指正,如有問題不妨看看別人的部落格 給乙個序列 要求最短的序列 使得對於所有 i m 有 a i sum f k a 主要思想是依次考慮每個 a i 不斷修改 使得其在保證正確的同時盡量短 一開始 為空 對每個 a i 判斷當前遞推式是否滿足條件 如果滿足...
演算法學習 Union Find演算法
union find演算法有它的實際用途。多用於動態連通的應用場景。union find演算法是 給出兩個節點,判斷它們是否連通,如果連通,是不需要給出具體的路徑的 舉兩個例子作為主要表現 1 在網路連線中,當發現沒有連線的兩個節點,可以把他們連線起來,一旦節點都連線起來,又能把多餘的線拆除,這時候...
演算法學習 KM演算法
km演算法 用於求二分圖的最佳完美匹配 即權值最大的完美匹配 如果你也是個剛來學習km演算法的人 大概的用途肯定還是知道的吧 還是直接說重點吧 首先 理解km演算法前 必須有以下3個概念 1.可行頂標 對於乙個賦值二分圖g x,y,e,w x,y 代表二分圖的兩邊頂點標號 e代表邊 w代表邊的權值 ...