BM算法


BM算法

用來求解一個數列的遞推式。
即給定\(\{x_i\}\)求解一個\(\{a_i\}\),滿足\(|a|=m,x_n=\sum_{i=1}^ma_i*x_{n-i}\)

考慮增量法構造。
假設當前有一個長度為\(m\)\(\{a\}\)滿足條件,並且對於\(x_{1..n-1}\)都滿足遞推關系。
定義\(delta=\sum_{i=1}^m a_i*x_{n-i}-x_i\)。如果\(delta\)顯然滿足遞推關系,不用管。
否則不滿足,那么我們就要\(fix\)一下鍋。那么我們就要找另外一個遞推式\(\{b\}\),讓\(i\in[1,n-1]\)的時候算出來的\(delta'\)都是\(0\),同時在\(i=n\)的時候算出來的東西是\(1\),那么乘一乘,搞一搞就可以了。
問題在於怎么找這個東西。如果當前這個不是第一次不合法,那么前面必定存在一個位置\(j\),然后在\(j\)的時候我們對於這個多項式修了一次鍋,它滿足了\([1,j-1]\)都是\(0\),同時\(j\)位置上有值。那么我們在前面補零,直到當前\(i\)位置的時候恰好對應到\(j\)位置上那個非\(0\)的位置,乘逆元之后,這樣子恰好能夠滿足條件。那么把多項式加在一起就好啦。

說得好亂啊,看看代碼就懂了。

模板

void BM()
{
	n=read();
	for(int i=1;i<=n;++i)f[i]=read();
	for(int i=1;i<=n;++i)
	{
		delta[i]=(MOD-f[i])%MOD;
		for(int j=0,l=now.size();j<l;++j)add(delta[i],1ll*f[i-j-1]*now[j]%MOD);
		if(!delta[i])continue;fail[cnt]=i;
		if(!cnt){now.resize(i);++cnt;continue;}
		int inv=(MOD-1ll*delta[i]*fpow(delta[fail[lst]],MOD-2)%MOD)%MOD,l=pre.size();
		cur.clear();cur.resize(i-fail[lst]-1);cur.push_back(MOD-inv);
		for(int j=0;j<l;++j)cur.push_back(1ll*inv*pre[j]%MOD);
		if(now.size()>cur.size())cur.resize(now.size());
		for(int j=0,l=now.size();j<l;++j)add(cur[j],now[j]);
		if(now.size()-i<pre.size()-fail[lst])lst=cnt,pre=now;
		++cnt;now=cur;
	}
	for(int i=0,l=now.size();i<l;++i)printf("%d ",now[i]);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM