hdu-6900
思路来源:penguin 学长
【题面大意】
给定多项式 \(\displaystyle f_1(x)=\sum_{i=0}^na_ix^i\) 与序列 \(\{b_n\},\{c_n\}\) 。已知递推式 \(f_n=b_nf_{n-1}'+c_nf_{n-1}(n>1)\) ,求 \(f_n\) 。
【分析】
展开几项得到:
\(\therefore f_n=b_nf_{n-1}'+c_nf_{n-1}\)
\(\qquad\ =b_n(b_{n-1}f'_{n-2}+c_{n-1}f_{n-2})'+c_n(b_{n-1}f'_{n-2}+c_{n-1}f_{n-2})\)
\(\qquad\ =b_nb_{n-1}f^{(2)}_{n-2}+(b_nc_{n-1}+b_{n-1}c_n)f^{(1)}_{n-2}+c_nc_{n-1}f^{(0)}_{n-2}\)
\(\qquad\ =b_nb_{n-1}b_{n-2}f^{(3)}_{n-3}+(b_nb_{n-1}c_{n-2}+b_nc_{n-1}b_{n-2}+c_nb_{n-1}b_{n-2})f^{(2)}_{n-3}+(b_nc_{n-1}c_{n-2}+c_nb_{n-1}c_{n-2}+c_nc_{n-1}b_{n-2})f^{(1)}_{n-3}+c_nc_{n-1}c_{n-2}f^{(0)}_{n-3}\)
观察式子可得,系数最终与 \(\displaystyle \prod_{i=2}^n(c_ix+b_i)\) 相同。
可证明确实相同
令 \(\displaystyle D(x)=\prod_{i=2}^n(c_ix+b_i)=\sum_{i=0}^{n-1}d_ix^i\)
\(\therefore \displaystyle f_n=d_0f_1^{(n-1)}+d_1f_1^{(n-2)}+d_2f_1^{(n-3)}+\cdots d_{n-1}f_1^{(0)}=\sum_{i=0}^{n-1}d_{n-1-i}f_1^{(i)}\)
\(\therefore \displaystyle f_n[m]=\sum_{i=0}^{n-1}d_{n-1-i}f_1^{(i)}[m]\)
考虑 \(f^{(i)}[m]=f_1^{(i-1)}[m+1]\cdot (m+1)=\cdots =f_1[m+i]\cdot {(m+i)!\over m!}\)
故代入移项得 \(\displaystyle m!\cdot f_n[m]=\sum_{i=0}^{n-1}d_{n-1-i}\cdot (m+i)!\cdot f_1[m+i]\)
令 \(e_i=i!\cdot f_1[i]\)
故 \(\displaystyle m!\cdot f_n[m]=\sum_{i=0}^{n-1}d_{n-1-i}e_{m+i}=(D\cdot E)[n-1+m]\)
因此最后可以卷积求得,复杂度为 \(O(n\log n)\)
而前面的 \(D(x)\) ,可以考虑分治求解:
设前 \({n\over 2}\) 项合并,后 \({n\over 2}\) 项合并,此时合并这两项,复杂度为 \(O(n\log n)\) 。
而前后两项的合并可以递归处理,故根据主定理 \(T(n)=2T({n\over 2})+O(n\log n)\) ,可以解得复杂度为 \(O(n\log^2 n)\) 。
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e6+10,MOD=998244353,inv3=(MOD+1)/3,Lim=1<<21;
int N,F[Lim],D[20][2][Lim],E[Lim],Frac[MAXN],InF[MAXN],C[MAXN],B[MAXN],POmega[22],NOmega[22];
inline int fpow(int a,int x) { int ans=1; for(;x;x>>=1,a=1ll*a*a%MOD) if(x&1) ans=1ll*ans*a%MOD; return ans; }
inline int inv(int a) { return fpow(a,MOD-2); }
inline void pre(){
Frac[0]=1;
for(register int i=1;i<=2e6;++i) Frac[i]=1ll*Frac[i-1]*i%MOD;
InF[2000000]=inv(Frac[2000000]);
for(register int i=2e6;i>=1;--i) InF[i-1]=1ll*InF[i]*i%MOD;
POmega[21]=fpow(3,MOD>>21);
for(register int i=20;i>=0;--i) POmega[i]=1ll*POmega[i+1]*POmega[i+1]%MOD;
NOmega[21]=fpow(inv3,MOD>>21);
for(register int i=20;i>=0;--i) NOmega[i]=1ll*NOmega[i+1]*NOmega[i+1]%MOD;
}
inline int add(int a,int b) { return (a+b>=MOD)?(a+b-MOD):(a+b); }
inline int dis(int a,int b) { return (a-b<0)?(a-b+MOD):(a-b); }
int L,Rev[Lim],invL;
inline void preNTT(){
Rev[1]=L>>1;
for(register int i=2;i<L;++i) Rev[i]=(Rev[i>>1]>>1)|Rev[i&1];
invL=inv(L);
}
inline void NTT(int f[Lim],int Omega[22],int op){
for(register int i=1;i<L;++i) if(i<Rev[i]) swap(f[i],f[Rev[i]]);
for(register int bas=2,mid=1,lb=1;bas<=L;bas<<=1,mid<<=1,++lb)
for(register int l=0,omega=Omega[lb],buf;buf=1,l<L;l+=bas)
for(register int k=l,tmp;tmp=1ll*buf*f[k+mid]%MOD,k<mid+l;++k,buf=1ll*buf*omega%MOD)
f[k+mid]=dis(f[k],tmp),f[k]=add(f[k],tmp);
if(op==-1){
for(register int i=0;i<L;++i) f[i]=1ll*invL*f[i]%MOD;
}
}
inline void mul(int f[Lim],int g[Lim],int h[Lim],int N,int M){
static int p[Lim],q[Lim];
L=1;
while(L<N+M+1) L<<=1;
preNTT();
for(register int i=0;i<L;++i) p[i]=q[i]=0;
for(register int i=0;i<=N;++i) p[i]=f[i];
for(register int i=0;i<=M;++i) q[i]=g[i];
NTT(p,POmega,1);
NTT(q,POmega,1);
for(register int i=0;i<L;++i) h[i]=1ll*p[i]*q[i]%MOD;
NTT(h,NOmega,-1);
}
void mergePoly(int Head,int Tail,int Dep,int isLeft,int Len){
if(Head==Tail){
D[Dep][isLeft][1]=C[Head];
D[Dep][isLeft][0]=B[Head];
return ;
}
mergePoly(Head,Head+Tail>>1,Dep+1,0,Len+1>>1);
mergePoly(Head+Tail+2>>1,Tail,Dep+1,1,Len+1>>1);
mul(D[Dep+1][0],D[Dep+1][1],D[Dep][isLeft],Len+1>>1,Len+1>>1);
for(register int i=0;i<L;++i) D[Dep+1][0][i]=D[Dep+1][1][i]=0;
}
inline void work(){
cin>>N;
for(register int i=0;i<=N;++i) cin>>E[i],E[i]=1ll*E[i]*Frac[i]%MOD;
for(register int i=2;i<=N;++i) cin>>B[i];
for(register int i=2;i<=N;++i) cin>>C[i];
mergePoly(2,N,1,0,N-1);
mul(D[1][0],E,F,N,N);
cout<<F[N-1];
for(register int i=1;i<=N;++i) cout<<' '<<1ll*F[i+N-1]*InF[i]%MOD;
for(register int i=0;i<L;++i) E[i]=B[i]=C[i]=F[i]=D[1][0][i]=0;
cout<<'\n';
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
pre();
int T;
cin>>T;
while(T--) work();
cout.flush();
return 0;
}