多项式应用

常系数齐次线性递推

求一个\(k\)阶齐次线性递推数列\(a\)的第\(n\)项。

给定这个数列的前\(k\)\(a_0,a_1,\cdots,a_n\),和递推系数\(f_1,f_2,\cdots,f_k\)

表示

\[a_n=\sum\limits_{i=1}^{k}f_i\times a_{n-i} \]

矩阵优化

矩阵快速幂不能通过,但是是重要的思想

设转移矩阵为\(A\),假设我们构造出序列\(c\),使得

\[A^n=\sum\limits_{i=0}^{k-1}c_iA^i \]

两边同时乘上初始行向量\(a\),注意到矩阵乘法的分配律

\[a\cdot A^n=\sum\limits_{i=0}^{k-1}c_i\cdot a\cdot A^i \]

因为我们最终只需要求行向量的第\(0\)

\[ans=(a\cdot A^n)_0=\sum\limits_{i=0}^{k-1}c_i\cdot (a\cdot A^i)0 \]

注意到等式右边,\(a\)是初始序列,\(A^i\)\(i\)次转移的矩阵,那么\((a\cdot A^i)\)就是\(i\)次转移之后的向量,\((a\cdot A^i)_0\)就是\(i\)次转移之后的第\(0\)个,即原序列的第\(i​\)

那么

\[ans=\sum\limits_{i=0}^{k=1}a_ic_i \]

多项式科技

问题转化为求\(c_i\),满足\(A^n=\sum\limits_{i=0}^{k-1}c_iA^i\),右边是一个关于\(A\)的多项式

因为\(\sum\limits_{i=0}^{k-1}c_iA^i\)的次数较小,考虑它是\(A^n\ \bmod\)另一个关于矩阵的多项式\(G(A)\)之后的余项

\(A^n\)换一种形式

\[A^n=Q(A)G(A)+\sum\limits_{i=0}^{k-1}c_iA^i \]

\(G(A)\)满足\(G(A)=0\),即

\[\sum\limits_{i=0}^kg_iA^i=0 \]

\(A\)视为一个数\(x\),问题再一次转化,成为求\(G\),然后快速幂对\(G\)取模,即可得到一个关于\(A\)的多项式\(R(A)=\sum\limits_{i=0}^{k-1}c_iA^i\)

有结论

\[g_{k-i}=-a_i,g_k=1 \]

然后多项式取模即可

scan(n);scan(k);
init_poly(k+k-1);
for(int i=1;i<=k;++i){
	scan(f[i]);f[i]=dec(f[i]%mod,0);
	R[k-i]=mod-f[i];
}
R[k]=1;
INVG=R;INVG.rev();INVG=Basic::poly_inv(INVG,k+1);
for(int i=0;i<k;++i){
	scan(a[i]);a[i]=dec(a[i]%mod,0);
}
B[1]=1;F[0]=1;
for(;n;n>>=1,B=(B*B)%R)if(n&1)F=(F*B)%R;
int ans=0;for(int i=0;i<k;++i)Add(ans,1ll*F[i]*a[i]%mod);
printf("%d",ans);

多项式多点求值

给定多项式\(f(x)\),以及\(m\)个数\(a_i\),表示\(m\)次询问\(f(a_i)\)的值

多项式科技

同上面的思路,将\(F(x)\)表示成\(F(x)=Q(x)G(x)+R(x)\)的形式。构造一个\(G(x_0)\),使得\(G(x_0)=0\),那么就有\(F(x_0)=R(x_0)\)

就再一次变成了多项式取模,最后答案即为\(F\)取模后的常数项(因为只剩这一项了)

\(G(x)\)的构造也很好想:\(G(x)=x-x_0\)

但是每次都直接取模时间无法承受

线段树分治

\(F(x)\)分别对\(\prod\limits_{i=l}^{mid}(x-x_i)\)\(\prod\limits_{i=mid+1}^{r}(x-x_i)\)取模,两边递归分治即可

显然这个就是线段树分治的形式

poly tr[N];
#define lid (id<<1)
#define rid (id<<1|1)
#define mid ((l+r)>>1)
void build(int id,int l,int r){
	if(l==r){tr[id][0]=mod-a[l];tr[id][1]=1;return;}
	build(lid,l,mid);build(rid,mid+1,r);
	tr[id]=tr[lid]*tr[rid];
}
int ans[N];
void work(int id,int l,int r,poly f){
	f=f%tr[id];if(l==r){ans[l]=f[0];return;}
	work(lid,l,mid,f);
	work(rid,mid+1,r,f);
}
int main(){
	scan(n);++n;scan(m);F.Read(n);
	init_poly(max(n<<1,m<<1)+5);
	for(int i=1;i<=m;++i)scan(a[i]);
	build(1,1,m);
	work(1,1,m,F);
	for(int i=1;i<=m;++i)putint(ans[i],'\n');
}
posted @ 2021-05-06 20:19  harryzhr  阅读(90)  评论(0编辑  收藏  举报