Berlekamp-Massey 算法(求数列的最短递推式)

用于求数列的最短递推式。

本文参考自 https://www.cnblogs.com/jz-597/p/14983564.html

增量法,设 \(R_i\) 表示第 \(i\) 个历史递推式,当前为 \(R_{cnt}\)

\(\Delta\) 表示真实的 \(a_i\) 与用 \(R_{cnt}\) 求出的 \(a_i\) 的差值,即 \(\Delta=a_i-\sum_{j=1}^{|R_{cnt}|}a_{i-j}R_{cnt,j}\)

  • \(\Delta=0\),则无事发生,跳过。
  • \(\Delta\neq 0\),那么我们需要调整这个递推式使得它对 \(a_i\) 也成立。

接下来看第二种情况怎么处理。

有一个想法是找到另一个递推式,使得这个递推式在算 \(\cdots,a_{i-1}\) 时取 \(0\),在算 \(a_i\) 时取 \(\Delta\)

我们可以找到一个历史递推式 \(R_{lst}\),设其失配位置为 \(fail_{lst}\),失配时的差值为 \(\Delta_{lst}\)(显然 \(\Delta_{lst}\neq 0\))。

\(d=\dfrac{\Delta}{\Delta_{lst}}\),那么我们可以找到这么一个递推式 \(R'=\{0,0,\cdots,0,d,-d\cdot R_{lst,1},-d\cdot R_{lst,2},\cdots\}\),其中前面是 \(i-fail_{lst}-1\)\(0\)

可以发现,使用这个递推式得到的 \(a_i'=\sum_{j=1}^{|R'|}R'_{j}a_{i-j}=d(a_{fail_{lst}}-\sum_{j=1}^{|R_{lst}|}R_{lst,j}a_{fail_{lst}-j})=d\cdot \Delta_{lst}=\Delta\)

而对于任意 \((i-k)\in [|R'|+1,i-1]\)\(a_{i-k}'=\sum_{j=1}^{|R'|}R'_j{a_{(i-k)-j}}=d(a_{fail_{lst}-k}-\sum_{j=1}^{|R_{lst}|}R_{lst,j}a_{(fail_{lst}-k)-j})=0\)

那么我们令 \(R_{cnt+1}\gets R_{cnt}+R'\) 即可。

实质上是利用了以前的信息 \(R_{lst}\):注意到失配前的差值都是 \(0\),所以我们用差值来定义递推式。

那么我们怎么找到最短的 \(R'\) 呢?由于 \(|R'|=i+\big(|R_{lst}|-fail_{lst}\big)\),所以我们直接找 \(|R_{lst}|-fail_{lst}\) 最小的就好了。

至于为什么求出来的递推式一定是最短的不会证。

【XSY3403】求数列的最短递推式 代码:

#include<bits/stdc++.h>

#define N 10010

using namespace std;

namespace modular
{
    const int mod=1000000007;
    inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
    inline int mul(int x,int y){return 1ll*x*y%mod;}
    inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
}using namespace modular;

inline int poww(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1) ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
    }
    return ans;
}

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=(x<<1)+(x<<3)+(ch^'0');
        ch=getchar();
    }
    return x*f;
}

int n,a[N],delta[N],fail[N];

vector<int>r[N];

int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    int cnt=0,lst=cnt;
    for(int i=1;i<=n;i++)
    {
        delta[cnt]=0;
        for(int j=0;j<r[cnt].size();j++)
            Add(delta[cnt],mul(r[cnt][j],a[i-j-1]));
        delta[cnt]=dec(a[i],delta[cnt]);
        if(!delta[cnt]) continue;
        fail[cnt]=i;
        if(!cnt)
        {
            r[++cnt].resize(i);
            continue;
        }
        r[cnt+1]=r[cnt];
        r[cnt+1].resize(max((int)r[cnt+1].size(),i+(int)r[lst].size()-fail[lst]));
        int d=mul(delta[cnt],poww(delta[lst],mod-2));
        Add(r[cnt+1][i-fail[lst]-1],d);
        for(int j=0;j<r[lst].size();j++)
            Add(r[cnt+1][i-fail[lst]+j],mul(dec(0,d),r[lst][j]));
        if((int)r[cnt].size()-fail[cnt]<(int)r[lst].size()-fail[lst]) lst=cnt;
        cnt++;
    }
    printf("%d\n1000000006 ",(int)r[cnt].size());
    for(int i=0;i<r[cnt].size();i++)
        cout<<r[cnt][i]<<" \0"[i==r[cnt].size()-1];
    return 0;
}
posted @ 2022-10-31 08:15  ez_lcw  阅读(100)  评论(0编辑  收藏  举报