多项式应用

常系数齐次线性递推

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

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

表示

[a_n=sumlimits_{i=1}^{k}f_i imes a_{n-i} ]

矩阵优化

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

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

[A^n=sumlimits_{i=0}^{k-1}c_iA^i ]

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

[acdot A^n=sumlimits_{i=0}^{k-1}c_icdot acdot A^i ]

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

[ans=(acdot A^n)_0=sumlimits_{i=0}^{k-1}c_icdot (acdot A^i)0 ]

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

那么

[ans=sumlimits_{i=0}^{k=1}a_ic_i ]

多项式科技

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

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

(A^n)换一种形式

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

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

[sumlimits_{i=0}^kg_iA^i=0 ]

(A)视为一个数(x),问题再一次转化,成为求(G),然后快速幂对(G)取模,即可得到一个关于(A)的多项式(R(A)=sumlimits_{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))分别对(prodlimits_{i=l}^{mid}(x-x_i))(prodlimits_{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],'
');
}
原文地址:https://www.cnblogs.com/harryzhr/p/14736759.html