Luogu5273 【模板】多項式冪函式 (加強版)
阿新 • • 發佈:2021-01-01
Luogu5273 【模板】多項式冪函式 (加強版)
注意細節,首先,對於前面有\(0\)的位需要進行平移,直到出現一個非\(0\)數(特判\(0\)過多的情況)。
同時我們需要把常數項變成\(1\)才能進行\(\ln\),也就是我們需要讓原多項式全體除以那個數,最後再乘回去。
對於那個數,我們進行快速冪需要用\(p-1\)(即\(\varphi(p)\)),這是費馬小定理決定的;而進行多項式快速冪時只需要對\(p\)取模,這兩者原理不同。
\(Code:\)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define N 300005 #define ll long long using namespace std; const int p=998244353; int n,k,k2,tn,cf=1,z0,w,s,l,G[2][35],inv[N],rev[N]; int a[N],b[N],c[N],d[N],e[N],f[N],g[N],h[N],r[N]; bool flag=false; void ReadK(int &k,int &k2) { ll s=0,s2=0; char c=getchar(); while (c<'0' || c>'9') c=getchar(); while ('0'<=c && c<='9') { s=(s << 3)+(s << 1)+(c^48); s2=(s2 << 3)+(s2 << 1)+(c^48); if (s>p) flag=true,s%=p; s2%=(p-1); c=getchar(); } k=s,k2=s2; } void Add(int &x,int y) { x=(x+y)%p; } void Del(int &x,int y) { x=(x-y+p)%p; } void Mul(int &x,int y) { x=(ll)x*y%p; } int add(int x,int y) { return (x+y)%p; } int del(int x,int y) { return (x-y+p)%p; } int mul(int x,int y) { return (ll)x*y%p; } int ksm(int x,int y) { int ans=1; while (y) { if (y & 1) Mul(ans,x); Mul(x,x); y >>=1; } return ans; } void Pre() { G[0][23]=ksm(3,(p-1)/(1 << 23)); G[1][23]=ksm(G[0][23],p-2); for (int i=22;i;--i) { G[0][i]=mul(G[0][i+1],G[0][i+1]); G[1][i]=mul(G[1][i+1],G[1][i+1]); } inv[1]=1; for (int i=2;i<=300000;++i) inv[i]=mul(p-p/i,inv[p%i]); } void solve(int n) { s=1,l=0; while (s<n) s <<=1,++l; for (int i=0;i<s;++i) rev[i]=(rev[i >> 1] >> 1) | ((i & 1) << l-1); } void NTT(int *a,int t) { for (int i=0;i<s;++i) if (i<rev[i]) swap(a[i],a[rev[i]]); for (int mid=1,o=1;mid<s;mid <<=1,++o) for (int j=0;j<s;j+=mid << 1) { int g=1; for (int k=0;k<mid;++k,Mul(g,G[t][o])) { int x=a[j+k],y=mul(g,a[j+k+mid]); a[j+k]=add(x,y),a[j+k+mid]=del(x,y); } } } void Cut(int *a,int n,int s) { memset(a+n+1,0,(s-n)*sizeof(int)); } void GetInv(int *f,int *g,int R) { if (R==2) { g[0]=ksm(f[0],p-2); return; } GetInv(f,g,R >> 1); memcpy(c,g,(R >> 2)*sizeof(int)),memcpy(d,f,(R >> 1)*sizeof(int)); solve(R); NTT(c,0),NTT(d,0); for (int i=0;i<s;++i) c[i]=del(add(c[i],c[i]),mul(d[i],mul(c[i],c[i]))); NTT(c,1); for (int i=0;i<s;++i) Mul(c[i],inv[s]); memcpy(g,c,(R >> 1)*sizeof(int)); memset(c,0,s*sizeof(int)),memset(d,0,s*sizeof(int)); } void Dev(int *a,int *b,int n) { for (int i=1;i<n;++i) b[i-1]=mul(a[i],i); } void InvDev(int *a,int *b,int n) { for (int i=0;i<n;++i) b[i+1]=mul(a[i],inv[i+1]); } void GetLn(int *f,int *g,int n) { s=1; while (s<n) s <<=1; s <<=1; GetInv(f,a,s); Cut(a,n,s); Dev(f,b,n); solve(n << 1); NTT(a,0),NTT(b,0); for (int i=0;i<s;++i) Mul(a[i],b[i]); NTT(a,1); for (int i=0;i<s;++i) Mul(a[i],inv[s]); InvDev(a,g,n); Cut(g,n,s); memset(a,0,s*sizeof(int)),memset(b,0,s*sizeof(int)); } void GetExp(int *f,int *g,int R) { if (R==2) { g[0]=1; return; } GetExp(f,g,R >> 1); GetLn(g,h,R >> 1); for (int i=0;i<(R >> 1);++i) h[i]=del(f[i],h[i]); Add(h[0],1); memcpy(e,g,(R >> 1)*sizeof(int)); solve(R); NTT(e,0),NTT(h,0); for (int i=0;i<s;++i) Mul(e[i],h[i]); NTT(e,1); for (int i=0;i<s;++i) Mul(e[i],inv[s]); memcpy(g,e,(R >> 1)*sizeof(int)); memset(e,0,s*sizeof(int)),memset(h,0,s*sizeof(int)); } int main() { Pre(); scanf("%d",&n),tn=n; ReadK(k,k2); for (int i=0;i<n;++i) scanf("%d",&r[i]); z0=0; while (z0<n && !r[z0]) ++z0; if (z0 && (z0==n || flag || (ll)z0*k>n)) { for (int i=0;i<n;++i) putchar('0'),putchar(' '); putchar('\n'); return 0; } w=z0*k; if (z0) { for (int i=z0;i<n;++i) r[i-z0]=r[i]; Cut(r,n-z0,n); n=n-z0; } cf=r[0]; int iv=ksm(cf,p-2); for (int i=0;i<n;++i) Mul(r[i],iv); cf=ksm(cf,k2); GetLn(r,f,n); for (int i=0;i<n;++i) Mul(f[i],k); s=1; while (s<n) s <<=1; s <<=1; GetExp(f,g,s); for (int i=tn-1;i>=w;--i) g[i]=g[i-w]; for (int i=0;i<w;++i) g[i]=0; for (int i=0;i<tn;++i) Mul(g[i],cf); for (int i=0;i<tn;++i) printf("%d ",add(g[i],p)); putchar('\n'); return 0; }