Berlekamp-Massey 算法

整了个比较精简的线性递推之后算是敢写各种需要线性递推的东西了。

这玩意的用处是求数列的最短线性递推式。实际上的用途一般就是打表。有时候也可以素质二连 \(O(k^2+k\log k\log n)\) 水过一些题(举个例子 joke3579 的 P8979 就是明白告诉你这是个线性递推)(joke3579 怒 d zhoukangyang)

Berlekamp-Massey 算法

设数列是 \(\{a_1,a_2,\cdots,a_n\}\),只考虑 \(\{a_1,\cdots,a_i\}\) 的递推式是 \(R_i\)。那么我们每次顺序往下扫一个数,此时可以计算 \(a_{i}\) 和用 \(R_{i-1}\) 推出来的数之差,记作 \(del_{i-1}\)。那么我们要求出 \(R_i\),需要:

  1. 如果 \(del=0\),那显然不用动。
  2. 如果 \(R_{i-1}\) 是空的,那么初始化放上去 \(i\)\(0\)
  3. 对于剩下的情况,我们对 \(R_{i-1}\) 的系数进行调整。可以找到之前最短的一个 \(R_w\),然后构造 \(R'=\{0,0,\cdots,0,\dfrac{del_{i-1}}{del_w},-\dfrac{del_{i-1}}{del_w}\times R_w\}\)\(0\)\(i-w-2\) 个。那么使得 \(R_i=R_{i-1}+R'\) 就是新的递推式。证明继续不会。

其实挺好背的。

void BM(int a[],int n,vector<int>&ans){
    int w=0,del=0;
    vector<int>lst;
    for(int i=1;i<=n;i++){
        int tmp=0;
        for(int j=0;j<ans.size();j++)tmp=(tmp+1ll*a[i-j-1]*ans[j])%mod;
        if((a[i]-tmp+mod)%mod==0)continue;
        if(!w){
            w=i;del=(a[i]-tmp+mod)%mod;
            for(int j=i;j;j--)ans.push_back(0);
            continue;
        }
        vector<int>now=ans;
        int mul=1ll*(a[i]-tmp+mod)*qpow(del,mod-2)%mod;
        if(ans.size()<lst.size()+i-w)ans.resize(lst.size()+i-w);
        ans[i-w-1]=(ans[i-w-1]+mul)%mod;
        for(int j=0;j<lst.size();j++)ans[i-w+j]=(ans[i-w+j]-1ll*mul*lst[j]%mod+mod)%mod;
        if(now.size()-i<lst.size()-w){
            lst=now;w=i;del=(a[i]-tmp+mod)%mod;
        }
    }
}
posted @ 2023-02-04 10:22  gtm1514  阅读(70)  评论(0编辑  收藏  举报