设
gn=∑ni=0{ni}2ii!
g
n
=
∑
i
=
0
n
{
n
i
}
2
i
i
!
,题目即求
∑ni=0gi
∑
i
=
0
n
g
i
。
考虑
gn
g
n
的组合意义,把
n
n
个元素放进个集合,这些集合有顺序之分,而且每个集合有两种状态,那么考虑枚举一个集合,
gn=∑ni=12(ni)gn−i
g
n
=
∑
i
=
1
n
2
(
n
i
)
g
n
−
i
。
展开组合数:
令 G(x)=∑∞i=0gii!xi,F(x)=∑∞i=12i!xi G ( x ) = ∑ i = 0 ∞ g i i ! x i , F ( x ) = ∑ i = 1 ∞ 2 i ! x i ,那么有:
+1 + 1 是因为 F(x) F ( x ) 是从 1 1 开始卷积的,要补上的常数项。
多项式求逆即可。
代码:
#include<iostream>
#include<cstdio>
#define ll long long
#define N 262150
using namespace std;
const int mod=998244353;
int n,m;
ll fac[N],ifac[N],f[N],g[N],c[N],r[N],ta[N],tb[N];
ll ksm(ll a,int b){ll r=1; for(b=(b+mod-1)%(mod-1);b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}
void ntt(ll *a,int n,int f)
{
for(int i=0;i<n;i++)
r[i]=(r[i>>1]>>1)|((i&1)*(n>>1));
for(int i=0;i<n;i++)
if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<n;i<<=1)
{
ll wn=ksm(3,(mod-1)*f/(i<<1));
for(int j=0;j<n;j+=(i<<1))
{
ll wk=1;
for(int k=j;k<j+i;k++,wk=wk*wn%mod)
{
ll x=a[k],y=wk*a[k+i]%mod;
a[k]=(x+y)%mod;a[k+i]=(x-y+mod)%mod;
}
}
}
if(f==-1) for(int i=0,tmp=ksm(n,mod-2);i<n;i++) a[i]=a[i]*tmp%mod;
}
void getinv(ll *a,ll *b,int n)
{
if(n==0){b[0]=ksm(a[0],mod-2);return ;}
getinv(a,b,n>>1);n<<=1;
for(int i=0;i<n;i++)
r[i]=(r[i>>1]>>1)|((i&1)*(n>>1));
for(int i=0;i<(n>>1);i++)
c[i]=a[i],c[i+(n>>1)]=0;
ntt(c,n,1);ntt(b,n,1);
for(int i=0;i<n;i++)
b[i]=((b[i]<<1)-c[i]*b[i]%mod*b[i]%mod+mod)%mod;
ntt(b,n,-1);
for(int i=(n>>1);i<n;i++) b[i]=0;
}
int main()
{
scanf("%d",&m);
for(n=1;n<=m;n<<=1);
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
ifac[n]=ksm(fac[n],mod-2);
for(int i=n-1;i>=0;i--)
ifac[i]=ifac[i+1]*(i+1)%mod;
f[0]=1;
for(int i=1;i<n;i++)
f[i]=((mod-ifac[i])<<1)%mod;
getinv(f,g,n);
ll ans=0;
for(int i=0;i<=m;i++)
ans=(ans+g[i]*fac[i])%mod;
printf("%lld",ans);
return 0;
}