Link
这是一个不需要推式子的清真做法。
首先我们把棋盘黑白染色,得到两个新的棋盘,然后分别在两个棋盘上算方案数(r,R)再卷起来就好了。
观察可得棋盘(B_1=(1,1,3,3,cdots),B_2=(2,2,4,4,cdots)),行数分别为(n,n-1)。
对于(B_1)运用Goldman-Joichi-White定理得到(sumlimits_{i=0}^nr_ix^{underline{n-i}}=x^{lfloorfrac n2
floor}(x+1)^{lceilfrac n2
ceil})。
对于(B_2)运用Goldman-Joichi-White定理得到(sumlimits_{i=0}^{n-1}R_ix^{underline{n-i}}=(x+2)^{lfloorfrac n2
floor}(x+1)^{lceilfrac n2
ceil-1})。
如果我们直接普通多项式转下降幂多项式就可以得到一个(O(nlog^2n))的辣鸡作法。
我们观察普通多项式转下降幂多项式的过程:多点求值,IFDT。
其中IFDT就是先变EGF再卷一个(e^{-x}),复杂度为(O(nlog n)),常数也很优秀。
而我们显然不需要多点求值,右边这个明摆着就能(O(nlog n))快速多点求值,常数比上面的IFDT更加优秀。
这样我们就可以得到两个下降幂多项式了,reverse一下就可以得到(r,R),再卷起来就好了。
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using std::reverse;
using u64=unsigned long long;
const int N=262150,P=998244353;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
void Put(char x){*oS++=x;if(oS==oT)Flush();}
int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(' ');}
}using namespace IO;
void swap(int&x,int&y){x^=y^=x^=y;}
int mod(int x){return x+(x>>31&P);}
int mul(int a,int b){return (u64)a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int w[N],ifac[N],r[N],lim;
void init(int n)
{
int l=33-__builtin_clz(n),g(pow(3,(P-1)>>l));
lim=1<<l,ifac[0]=w[lim>>1]=1,--l;
for(int i=1;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<l);
for(int i=1;i<=n;++i) ifac[i]=mul(ifac[i-1],pow(i,P-2));
for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
return ;
}
void NTT(int*a,int f)
{
if(!~f) reverse(a+1,a+lim);
static u64 t[N];
for(int i=0;i<lim;++i) t[r[i]]=a[i];
for(int i=1;i<lim;i<<=1) for(int j=0,d=i<<1;j<lim;j+=d) for(int k=0,x;k<i;++k) x=t[i|j|k]*w[i|k]%P,t[i|j|k]=t[j|k]+P-x,t[j+k]+=x;
for(int i=0;i<lim;++i) a[i]=t[i]%P;
if(!~f) for(int i=0,p=(P-(P-1)/lim);i<lim;++i) a[i]=mul(a[i],p);
}
int e[N],f[N],g[N];
int main()
{
int n=read();
if(n==1) return !printf("1");
init(n);
for(int i=0;i<=n;++i) e[i]=i&1? P-ifac[i]:ifac[i];
for(int i=1;i<=n;++i) f[i]=mul(mul(pow(i,n>>1),pow(i+1,(n+1)/2)),ifac[i]);
for(int i=0;i<n;++i) g[i]=mul(mul(pow(i+2,n>>1),pow(i+1,(n-1)/2)),ifac[i]);
NTT(e,1),NTT(f,1),NTT(g,1);
for(int i=0;i<lim;++i) f[i]=mul(f[i],e[i]),g[i]=mul(g[i],e[i]);
NTT(f,-1),NTT(g,-1),memset(f+n+1,0,(lim-n-1)<<2),memset(g+n,0,(lim-n)<<2),reverse(f,f+n+1),reverse(g,g+n),NTT(f,1),NTT(g,1);
for(int i=0;i<lim;++i) f[i]=mul(f[i],g[i]);
NTT(f,-1);
for(int i=1;i<n*2;++i) printf("%d ",f[i]);
}
段落引用