这个题堪称 简易模板全家桶。
关于各个函数的实现,大多数都是利用牛顿迭代公式+倍增。
下面的 分别为已知多项式,当前所求多项式和上一个状态(规模小一半)的多项式
以下证明略.
代码:
#include<ctime>
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++)
using namespace std;
typedef long long ll;
const int N=1<<18|10,g=3,G=332748118,mod=998244353;
char buf[N],*p1=buf,*p2=buf;
void qr(int &x) {
char c=gc; x=0;
while(!isdigit(c))c=gc;
while(isdigit(c))x=x*10+c-'0',c=gc;
}
void qw(int x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
int n,m,k,tr[N],f[N];
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
a=a*a%mod; b=b>>1;
}
return c;
}
namespace Cipolla {
ll w,n,p=mod;
struct CP {
ll x,y;
CP(ll x=1,ll y=0):x(x),y(y){}
CP operator *(CP b) const {
return CP( (x*b.x+y*b.y%p*w)%p , (x*b.y+y*b.x)%p );
}
};
CP Pow(CP a,ll b=p+1>>1) {
CP c;
for( ;b;b=b>>1,a=a*a)
if(b&1) c=c*a;
return c;
}
bool pd(ll x) {return power(x,p-1>>1)==p-1;}
int solve(ll t) {
n=t;
if(!n) return 0;
ll a;
do {
a=1LL*rand()*rand()%p;
w=( (a*a-n)%p+p )%p;
} while(!pd(w));
ll x=Pow(CP(a,1)).x,y=p-x;
if(x>y) return y;
return x;
}
}
int calc(int x) {//丢入长度
if(x==(x&-x)) return x;
int n=1;while(n<x)n<<=1;
return n;
}
void upd(int &a) {a+=a>>31&mod;}
int pre[2][22];
void NTT(int *f,int v,int n) {
for(int i=1;i<n;i++)
if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2,j=1;p<=n;p<<=1,j++) {
int len=p>>1;
ll tg=pre[v][j],buf,t;
for(int i=0;i<n;i+=p) {
buf=1;
for(int l=i;l<i+len;l++) {
t=f[l+len]*buf%mod;
upd(f[l+len]=f[l]-t);
upd(f[l] += t-mod);
buf=buf*tg%mod;
}
}
}
}
int a[N],b[N],w[N];
void mult(int *a,int *b,int n,int m) {
int *c=w;
n<<=1; for(int i=1;i<n;i++)tr[i]=(tr[i>>1]>>1)|(i&1?n>>1:0);
if(a!=b) {
for(int i=0;i*2<n;i++) c[i]=b[i];
for(int i=n>>1;i<n;i++) c[i]=0;
NTT(c,1,n);
}
else c=a;
NTT(a,1,n); for(int i=0;i<n;i++) a[i]=(ll)a[i]*c[i]%mod;
NTT(a,0,n); ll inv=power(n);
for(int i=0;i<m;i++) a[i]=a[i]*inv%mod;
for(int i=m;i<n;i++) a[i]=0;
}
void inv(int *f,int n) {
n=calc(n);
b[0]=power(f[0]);
for(int len=1,p=2;p<=n;len=p,p <<= 1) {
for(int i=0;i<len;i++)
upd(a[i]=2*b[i]-mod);
mult(b,b,len,p);mult(b,f,p,p);
for(int i=0;i<p;i++)
upd(b[i]=a[i]-b[i]);
}
for(int i=0;i<n;i++) f[i]=b[i],a[i]=b[i]=0;
}
int h[N],s[N];
void Sqrt(int *f,int n) {
n=calc(n);
s[0]=Cipolla::solve(f[0]);
for(int len=1,p=2;p<=n;len=p,p <<= 1) {
for(int i=0;i<p;i++) upd(h[i]=2*s[i]-mod);
inv(h,p); mult(s,s,len,p);
for(int i=0;i<p;i++) upd(s[i]+=f[i]-mod);
mult(s,h,p,p);
}
for(int i=0;i<n;i++) f[i]=s[i],h[i]=s[i]=0;
}
void Dao(int *a,int *b,int n) {
for(int i=1;i<n;i++) b[i-1]=(ll)a[i]*i%mod;
b[n-1]=0;
}
int Inv[N];//
void Ji(int *a,int *b,int n) {
for(int i=n-1; i;i--) b[i]=(ll)a[i-1]*Inv[i]%mod;
b[0]=0;
}
int c[N];
void Ln(int *f,int n) {
n=calc(n);Dao(f,c,n);
inv(f,n); mult(f,c,n,n);
Ji(f,f,n);
}
int e[N],E[N];
void Exp(int *f,int n) {
n=calc(n);
e[0]=1;
for(int p=2;p<=n;p<<=1) {
for(int i=0;i<p;i++) E[i]=e[i];
Ln(E,p); upd(--E[0]);
for(int i=0;i<p;i++) upd(E[i]=-E[i]+f[i]);
mult(e,E,p,p);
}
for(int i=0;i<n;i++) f[i]=e[i],e[i]=E[i]=0;
}
int tmp[N];
int main() {
srand(time(0));
qr(m); qr(k); m++; n=calc(m);
Inv[1]=1; for(int i=2;i<n;i++) Inv[i]=(ll)Inv[mod%i]*(mod-mod/i)%mod;
for(int i=1;i<20;i++)
pre[0][i]=power(G,mod>>i),
pre[1][i]=power(g,mod>>i);
for(int i=0;i<m;i++) qr(f[i]),tmp[i]=f[i];
Sqrt(tmp,n);inv(tmp,n);Ji(tmp,tmp,n);Exp(tmp,n);
for(int i=0;i<n;i++) upd(tmp[i]=f[i]-tmp[i]);
upd(tmp[0]=(tmp[0]+2-f[0])%mod);
Ln(tmp,n); tmp[0]=(tmp[0]+1)%mod;
Ln(tmp,n); for(int i=0;i<n;i++) tmp[i]=(ll)tmp[i]*k%mod;
Exp(tmp,n);Dao(tmp,tmp,n);
for(int i=0;i<m-1;i++)qw(tmp[i]),putchar(' ');
return 0;
}