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)


【分析】

展开几项得到:

( herefore 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)

( herefore 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)})

( herefore 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}=(Dcdot E)[n-1+m])

因此最后可以卷积求得,复杂度为 (O(nlog n))

而前面的 (D(x)) ,可以考虑分治求解:

设前 ({nover 2}) 项合并,后 ({nover 2}) 项合并,此时合并这两项,复杂度为 (O(nlog n))

而前后两项的合并可以递归处理,故根据主定理 (T(n)=2T({nover 2})+O(nlog n)) ,可以解得复杂度为 (O(nlog^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<<'
';
}
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;
}
原文地址:https://www.cnblogs.com/JustinRochester/p/13705300.html