BM算法,可以求一个数列的最短递推式。
采用增量法,依次考虑每个数:
若在这个位置上正确,则忽略;
否则,类似拉格朗日插值法,找一个满足在前面位置都为0,这个位置上不为0的递推式,进行修补。
每当我们遇到一个这样的位置时,我们都可以得到一个这样的递推式:用目前的递推式,在0位置(即这个位置上),增加一个-1。相当于积累了一个“经验”。
这样,我们在所有的“经验”中,找到一个,并在它的前面补0,相当于移位。
若有多个,取补0后长度最小的。
时间复杂度:\(O(n(n+m))\)。(n为递推式长度,m为输入长度)。
代码:
int BM(int sz[10010],int n)
{
int m=0;
for(int i=1;i<=n;i++)
{
cd[i]=inf;
int he=(md-sz[i])%md;
for(int j=1;j<=m;j++)
he=(he+1ll*ans[j]*sz[i-j])%md;
if(he==0)
continue;
int ny=ksm(he,md-2);
sb[i][0]=(md-ny)%md;
for(int j=1;j<=m;j++)
sb[i][j]=1ll*ans[j]*ny%md;
cd[i]=m;int mi=inf,wz;
for(int j=0;j<i;j++)
{
int t=cd[j]+(i-j);
if(t<=mi)
mi=t,wz=j;
}
for(int j=0;j<=cd[wz];j++)
ans[i-wz+j]=(ans[i-wz+j]-1ll*sb[wz][j]*he%md+md)%md;
if(mi>m)m=mi;
}
return m;
}