多项式应用
常系数齐次线性递推
求一个\(k\)阶齐次线性递推数列\(a\)的第\(n\)项。
给定这个数列的前\(k\)项\(a_0,a_1,\cdots,a_n\),和递推系数\(f_1,f_2,\cdots,f_k\)
表示
矩阵优化
矩阵快速幂不能通过,但是是重要的思想
设转移矩阵为\(A\),假设我们构造出序列\(c\),使得
两边同时乘上初始行向量\(a\),注意到矩阵乘法的分配律
因为我们最终只需要求行向量的第\(0\)项
注意到等式右边,\(a\)是初始序列,\(A^i\)是\(i\)次转移的矩阵,那么\((a\cdot A^i)\)就是\(i\)次转移之后的向量,\((a\cdot A^i)_0\)就是\(i\)次转移之后的第\(0\)个,即原序列的第\(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\)换一种形式
\(G(A)\)满足\(G(A)=0\),即
将\(A\)视为一个数\(x\),问题再一次转化,成为求\(G\),然后快速幂对\(G\)取模,即可得到一个关于\(A\)的多项式\(R(A)=\sum\limits_{i=0}^{k-1}c_iA^i\)
有结论
然后多项式取模即可
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');
}