牛客國慶派對day4 導數卷積【NTT】
阿新 • • 發佈:2019-02-09
的第j項為
我們設
可以將上述式子化為
在題中的卷積中構成結果的係數的必為:
其中
把上面的用d和n-1代入消去p2和i2,然後換元搞搞就是卷積了
程式碼:
#include<bits/stdc++.h> #define ll long long const int N=3e5 + 5; const ll MOD=998244353;//50000000001507329LL;//998244353 1004535809 using namespace std; int n,m; ll a[N],b[N],x[N],y[N]; ll wn[25]; ll Mul(ll x,ll y)//乘法超ll用快速乘,主函式也需要用 { ll ans=(x*y-(ll)((long double)x/MOD*y+1e-8)*MOD); return ans<0?ans+MOD:ans; } ll Qpow(ll a,ll b,ll M) { ll ans=1;a%=M; while(b) { if(b&1) ans=Mul(ans,a); a=Mul(a,a); b>>=1; } return ans; } void Getwn()//主函式預處理getwn() { for(int i=0;i<25;i++) { wn[i]=Qpow(3,(MOD-1)/(1<<i),MOD); } } void NTT(ll *x,int n,int rev) { int i,j,k,ds; ll w,u,v; for(i=1,j=n>>1,k=n>>1;i<n-1;i++,k=n>>1) { if(i<j) swap(x[i],x[j]); while(j>=k) j-=k,k>>=1; if(j<k) j+=k; } for(i=2,ds=1;i<=n;i<<=1,ds++) { for(j=0;j<n;j+=i) { w=1; for(k=j;k<j+i/2;k++) { u=x[k]; v=Mul(w,x[k+i/2]); x[k]=(u+v)%MOD; x[k+i/2]=(u-v+MOD)%MOD; w=Mul(w,wn[ds]); } } } if(rev==-1) { for(i=1;i<n/2;i++) swap(x[i],x[n-i]); w=Qpow(n,MOD-2,MOD); for(i=0;i<n;i++) x[i]=Mul(x[i],w); } } int A[N]; ll fac[N], inv[N]; ll res1[N], res2[N]; void init() { fac[0]=1; for(int i=1;i<=100000;i++) fac[i] = fac[i-1] * i % MOD; inv[100000]=Qpow(fac[100000],MOD-2,MOD); for(int i=100000-1;i;i--) inv[i] = inv[i+1] * (i+1) % MOD; inv[0]=1; } int main() { Getwn(); init(); scanf("%d", &n); m=n; for(int i=0;i<n;i++)scanf("%d",&A[i]); for(int i=0;i<n;i++)a[i]=fac[n-1-i]*A[n-1-i]%MOD; for(int i=0;i<n;i++)b[i]=inv[i]; int len=1,s=n+m;//結果的係數長度 while(len<s)len<<=1; for(int i=n;i<len;i++)a[i]=0; for(int i=m;i<len;i++)b[i]=0;//不滿二進位制數補0 NTT(a,len,1);NTT(b,len,1);//化成點值表示式 for(int i=0;i<len;i++)res1[i]=Mul(a[i],a[i]),res2[i]=Mul(b[i],b[i]); NTT(res1,len,-1);NTT(res2,len,-1);//還原為多項式 for(int i=0;i<n;i++) res2[i]=res1[n-1-i]*res2[i]%MOD; for(int i=0;i<n;i++) { printf("%lld", res2[i]); if (i==n-1) printf("\n"); else printf(" "); } }