P4091 [HEOI2016/TJOI2016]求和
首先发现j是可以枚举到n的,因为j>i时s(i,j)为0。
把第二类斯特林数按照容斥的定义转换一下。
由于第二类斯特林数是一个卷积的形式,可以枚举i后ntt求解,复杂度O(n^2logn)
变换一下枚举的顺序,把i移到最内层。
发现可以预处理一下sigema i0+i1+i2+i3.....i^n然后就o(nlogn)了。
#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#define N 1100000
#define L 1100000
#define eps 1e-7
#define inf 1e9+7
#define db double
#define ll long long
#define ldb long double
using namespace std;
inline ll read()
{
char ch=0;
ll x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*flag;
}
const ll d=3,mo=998244353;
ll ksm(ll x,ll k)
{
ll ans=1;
while(k)
{
if(k&1)ans=1ll*ans*x%mo;
k>>=1;
x=1ll*x*x%mo;
}
return ans;
}
ll inv(ll x){return ksm(x,mo-2);}
ll rev[N];
void ntt(ll *f,ll n,ll flag)
{
for(ll i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)+(i&1)*(n>>1);
for(ll i=0;i<n;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
for(ll k=2,kk=1;k<=n;k<<=1,kk<<=1)
{
ll wn=ksm(d,(mo-1)/k);
if(flag==-1)wn=inv(wn);
for(ll i=0;i<n;i+=k)
for(ll j=0,w=1;j<kk;j++,w=1ll*w*wn%mo)
{
ll t=1ll*w*f[i+j+kk]%mo;
f[i+j+kk]=(f[i+j]-t+mo)%mo;
f[i+j]=(f[i+j]+t)%mo;
}
}
if(flag==-1)
{
ll k=inv(n);
for(ll i=0;i<n;i++)f[i]=(f[i]*k)%mo;
}
}
ll a[N],b[N];
void mul(ll len)
{
for(ll i=len;i<2*len;i++)a[i]=b[i]=0;
ntt(a,2*len,+1);ntt(b,2*len,+1);
for(ll i=0;i<2*len;i++)a[i]=1ll*a[i]*b[i]%mo;
ntt(a,2*len,-1);
}
ll f[N],fac[N];
int main()
{
ll n,len=read();
for(n=1;n<=len+1;n<<=1);
for(ll i=0;i<=len;i++)
{
fac[i]=i?((fac[i-1]*i)%mo):1;
if(i==0)f[i]=1;
else if(i==1)f[i]=len+1;
else f[i]=(ksm(i,len+1)-1)*inv((i-1))%mo;
}
for(ll i=0;i<=len;i++)
{
a[i]=(ksm(-1,i)*inv(fac[i])+mo)%mo;
b[i]=f[i]*inv(fac[i])%mo;
}
mul(n);
ll ans=0;
for(ll i=0;i<=len;i++)ans=(ans+((ksm(2,i)*fac[i]%mo*a[i])%mo))%mo;
printf("%lld",(ans%mo+mo)%mo);
return 0;
}