求逆和乘法过了,开根两天还没调出来,已经重构了一次代码,感觉可能是有些东西重复调用的问题,一直找不出来。(ntt)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
const int g=3,p=998244353;
const ll N=4e5+10;
ll n,m,a[N],c[N],b[N],d[N],e[N],f[N],lim=1,l;
inline ll ksm(ll a, ll k) {
ll base = 1;
while(k) {
if(k & 1) base = (base * a ) % p;
a = (a * a) % p;
k >>= 1;
}
return base % p;
}
void ntt(ll *a,ll type)
{
for(ll i=0;i<lim;i++){
if(i<c[i])swap(a[i],a[c[i]]);
}
for(ll mid=1;mid<lim;mid<<=1)
{
ll W=ksm(g,(p-1)/(mid<<1));
if(type==-1)W=ksm(W,p-2);
for(ll r=mid<<1,j=0;j<lim;j+=r)
{
ll w=1;
for(ll l=0;l<mid;l++,w=(w*W)%p)
{
ll x=a[j+l],y=w*a[j+mid+l]%p;
a[j+l]=(x+y+p)%p;a[j+mid+l]=(x-y+p)%p;
}
}
}
if(type==1) return;
ll inv=ksm(lim,p-2);
for(ll i=0;i<lim;i++)a[i]=(a[i]*inv)%p;
}
void mul(ll *a,ll *b,int len1,int len2)
{
ll l=0;
while(lim<=len1+len2)
{
lim<<=1;
l++;
}
for(ll i=0;i<lim;i++)c[i]=(c[i>>1]>>1)|((i&1)<<(l-1));
ntt(a,1);ntt(b,1);
for(ll i=0;i<lim;i++)
a[i]=a[i]*b[i]%p;
ntt(a,-1);
ll inv=ksm(lim,p-2);
for(ll i=0;i<=n+m;i++)a[i]=a[i]*inv;
for(ll i=n+m+1;i<lim;i++)a[i]=0;
}
void inv(ll *a,ll *b,int len)
{
if(len==1)
{
b[0]=ksm(a[0],p-2);
return ;
}
inv(a,b,(len+1)>>1);
l=0,lim=1;
while(lim<len*2)
{
lim<<=1;
l++;
}
for(int i=0;i<len;++i)d[i]=a[i];
for(int i=len;i<lim;i++)d[i]=0;
for(ll i=0;i<lim;i++)c[i]=(c[i>>1]>>1)|((i&1)<<(l-1));
ntt(a,1),ntt(d,1);ntt(b,1);
for(ll i=0;i<lim;i++)
b[i]=1ll*(2-1ll*d[i]*b[i]%p+p)%p*b[i]%p;
ntt(b,-1);
for(ll i=len;i<lim;i++)b[i]=0;
}
void sqrt(ll *a,ll *b,int len)
{
if(len==1)
{
b[0]=1;
return ;
}
sqrt(a,b,(len+1)>>1);
l=0,lim=1;
while(lim<len*2)
{
lim<<=1;
l++;
}
for(int i=0;i<lim;++i)d[i]=2*b[i]%p,e[i]=b[i],f[i]=0;
for(int i=len;i<lim;i++)e[i]=0;
mul(b,e,lim,lim);
inv(d,f,len);
ntt(b,1);ntt(a,1);
for(ll i=0;i<lim;i++)
b[i]=(b[i]+a[i]+p)%p;
ntt(b,-1);
mul(b,f,lim,lim);
for(int i=len;i<lim;i++)b[i]=0;
return ;
}
int main()
{
scanf("%d",&n);
int x;
for(ll i=0;i<n;i++)scanf("%d",&x),a[i]=(x+p)%p;
sqrt(a,b,n);
for(int i=0;i<n;i++)printf("%d ",b[i]);
return 0;
}