运算法则 | 算法 | 时间复杂度 |
---|---|---|
多项式乘法 | 快速傅里叶变换 | Θ ( n log 2 n ) \Theta(n\log_2 n) Θ(nlog2n) |
多项式求逆 | 倍增+快速数论变换 | Θ ( n log 2 n ) \Theta(n\log_2 n) Θ(nlog2n) |
多项式对数函数 | 求导+积分 | Θ ( n log 2 n ) \Theta(n\log_2 n) Θ(nlog2n) |
多项式指数函数 | 泰勒展开+牛顿迭代 | Θ ( n log 2 n ) \Theta(n\log_2 n) Θ(nlog2n) |
分治FFT卷积 | 分治FFT/多项式求逆 | Θ ( n log 2 2 n ) / Θ ( n log 2 n ) \Theta(n\log_2^2 n)/\Theta(n\log_2 n) Θ(nlog22n)/Θ(nlog2n) |
% 给定长度为 n − 1 n-1 n−1 的序列 g i g_i gi,其中 i ∈ [ 1 , n ) ∩ Z i\in [1,n)∩\Z i∈[1,n)∩Z,已知 f 0 = 1 f_0=1 f0=1,你需要对于每个 i i i 求出 f i = ∑ j = 1 i f i − j g j f_i=\sum_{j=1}^if_{i-j}g_j fi=j=1∑ifi−jgj 对 998244353 998244353 998244353 取模后的结果。
数据范围 2 ⩽ n ⩽ 1 0 5 , ∀ i ∈ [ 1 , n ) ∩ Z , 2\leqslant n\leqslant 10^5,\forall i\in[1,n)∩\Z\ ,\; 2⩽n⩽105,∀i∈[1,n)∩Z ,有 0 ⩽ g i < 998244353 0\leqslant g_i< 998244353 0⩽gi<998244353。
% 先来考虑一种不那么通用,但效率更高的方法。
% 不妨令 g 0 = 0 g_0=0 g0=0,下标超出 n n n 的部分也为 0 0 0,设 f i f_i fi 和 g i g_i gi 的生成函数分别为
F ( x ) = ∑ i = 0 ∞ f i x i G ( x ) = ∑ i = 0 ∞ g i x i \begin{aligned} F(x)=\sum_{i=0}^\infty f_ix^i\\ G(x)=\sum_{i=0}^\infty g_ix^i\\ \end{aligned} F(x)=i=0∑∞fixiG(x)=i=0∑∞gixi
% 则有(注意下标变化)
F ( x ) G ( x ) = ∑ i = 0 ∞ x i ( ∑ j = 0 i f i − j g j ) = ∑ i = 1 ∞ x i ( ∑ j = 1 i f i − j g j ) = ∑ i = 1 ∞ f i x i = ∑ i = 0 ∞ f i x i − f 0 = F ( x ) − f 0 \begin{aligned} F(x)G(x)&=\sum_{i=0}^\infty x^i\left(\sum_{j=0}^if_{i-j}g_j\right)\\ &=\sum_{i=1}^\infty x^i\left(\sum_{j=1}^if_{i-j}g_j\right)\\ &=\sum_{i=1}^\infty f_ix^i\\ &=\sum_{i=0}^\infty f_ix^i-f_0\\ &=F(x)-f_0\\ \end{aligned} F(x)G(x)=i=0∑∞xi(j=0∑ifi−jgj)=i=1∑∞xi(j=1∑ifi−jgj)=i=1∑∞fixi=i=0∑∞fixi−f0=F(x)−f0
% 整理,得 F ( x ) = f 0 [ 1 − G ( x ) ] − 1 F(x)=f_0[1-G(x)]^{-1} F(x)=f0[1−G(x)]−1
% 因而有 F ( x ) ≡ f 0 [ 1 − G ( x ) ] − 1 ( m o d x n ) F(x)≡f_0[1-G(x)]^{-1}\pmod{x^n} F(x)≡f0[1−G(x)]−1(modxn)
% 然后就只需要一个多项式求逆即可。
时间复杂度显然为 Θ ( n log 2 n ) \Theta(n\log_2 n) Θ(nlog2n)。
#include
#include
#include
using namespace std;
#define MAXN 4000010
const long long mod=998244353,G=3,inG=332748118;
long long pows(long long a,long long b){
long long ret=1;
while(b){
if(b&1) ret=ret*a%mod;
b>>=1;a=a*a%mod;
} return ret;
}
#define invt(x) pows(x,mod-2)
class poly{
public:
static const int maxn=MAXN;
long long *t;
int limit,l,inmit;
long long& operator[](int x){return t[x];}
const long long& operator[](int x)const{return t[x];}
poly(int n=0):t(NULL),limit(1),l(0){init(n);}
void init(int n){
if(limit>=n) return;
if(t) free(t);
while(limit<n) limit<<=1,++l;
inmit=invt(limit);
t=(long long*)calloc(limit+5,sizeof(long long));
}
void fnt(int type){
static long long r[MAXN];
static int now=0;
if(now!=limit&&(now=limit))
for(int i=1;i<limit;i++)
r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
for(int i=1;i<limit;i++)
if(i<r[i]) swap(t[i],t[r[i]]);
for(int mid=1;mid<limit;mid<<=1){
long long wn=pows(type==1?G:inG,(mod-1)/(mid<<1));
for(int j=0,B=(mid<<1);j<limit;j+=B){
long long w=1;
for(int k=0;k<mid;k++,w=w*wn%mod){
int x=t[j+k],y=w*t[j+k+mid]%mod;
t[j+k]=(x+y)%mod;t[j+k+mid]=(x-y+mod)%mod;
}
}
} if(type==-1) for(int i=0;i<limit;i++)
t[i]=t[i]*inmit%mod;
}
void inv(int n,poly &g)const{
g.init(n+n);
if(n==1) return (void)(g[0]=invt(t[0]));
inv((n+1)>>1,g);
poly a(n+n),b(n+n);
for(int i=0;i<n;i++)
a[i]=t[i],b[i]=g[i];
a.fnt(1);b.fnt(1);
for(int i=0;i<a.limit;i++)
a[i]=b[i]*((2-a[i]*b[i]%mod+mod)%mod)%mod;
a.fnt(-1);
for(int i=0;i<n;i++) g[i]=a[i];
}
}a,b;
int n;
int main(){
scanf("%d",&n);
a.init(n+n);b.init(n+n);
for(int i=1;i<n;i++)
scanf("%lld",&b[i]);
for(int i=1;i<n;i++)
b[i]=(mod-b[i])%mod;
b[0]=1;b.inv(n,a);
for(int i=0;i<n;i++)
printf("%lld ",a[i]);
return 0;
}