题目:
题解:
我的Ma呀这种东西应该给递推式吗?为什么不给我通项,于是我扪心自问不是TJ和HE选手,上网查了通项
S(n,m)=1m!∑k=0m(−1)kCkm(m−k)n
S
(
n
,
m
)
=
1
m
!
∑
k
=
0
m
(
−
1
)
k
C
m
k
(
m
−
k
)
n
好叭我就把ta代入到这个凶残的柿子里叭

这个第二项运行到i我就很不服了,改成n是不是好看一些?
随便改的基础是第二类斯特林数的情景:将n个不同的球放入m个无差别的盒子中,要求盒子非空的方案数,当n < m的时候,方案数自然是0呀
那么我们把改良后的柿子拿出来:
f(n)=∑i=0n∑j=0n∑k=1j(−1)kCkj(j−k)i∗2j
f
(
n
)
=
∑
i
=
0
n
∑
j
=
0
n
∑
k
=
1
j
(
−
1
)
k
C
j
k
(
j
−
k
)
i
∗
2
j
然后怎么办呢?似乎看起来有什么 (−1)k ( − 1 ) k 和 (j−k)i ( j − k ) i 让我们能够联想到卷积之类的东西,但那个组合数好像很碍事,那我们把它化成阶乘的形式。
f(n)=∑i=0n∑j=0n∑k=1j(−1)kj!k!(j−k)!(j−k)i∗2j
f
(
n
)
=
∑
i
=
0
n
∑
j
=
0
n
∑
k
=
1
j
(
−
1
)
k
j
!
k
!
(
j
−
k
)
!
(
j
−
k
)
i
∗
2
j
把与k和j-k无关的丢到外面去
f(n)=∑j=0n2j∗j!∑k=1j(−1)kk!∑ni=0(j−k)i(j−k)!
f
(
n
)
=
∑
j
=
0
n
2
j
∗
j
!
∑
k
=
1
j
(
−
1
)
k
k
!
∑
i
=
0
n
(
j
−
k
)
i
(
j
−
k
)
!
好叭这样后面的就可以卷积了,即 f(i)=(−1)ii! f ( i ) = ( − 1 ) i i ! , g(i)=∑nj=0iji! g ( i ) = ∑ j = 0 n i j i !
那么这个柿子的最终形态就是:
f(n)=∑j=0n2j∗j!∗∑kf(j)∗g(j−k)
f
(
n
)
=
∑
j
=
0
n
2
j
∗
j
!
∗
∑
k
f
(
j
)
∗
g
(
j
−
k
)
因为有一个模数,我们用NTT
代码:
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int N=300005;
const int mod=998244353;
LL a[N],b[N],ans,mi[N],mul[N],inv[N],invmul[N];int r[N],n,fn;
LL ksm(LL a,LL k)
{
LL ans=1;
for (;k;k>>=1,a=a*a%mod)
if (k&1) ans=ans*a%mod;
return ans;
}
void NTT(LL *a,int id)
{
for (int i=0;i<n;i++)
if (i<r[i]) swap(a[i],a[r[i]]);
for (int k=1;k<n;k<<=1)
{
LL wn=ksm(3,(mod-1)/(k<<1));
for (int i=0;i<n;i+=(k<<1))
{
LL w=1;
for (int j=0;j<k;j++,w=w*wn%mod)
{
LL x=a[i+j],y=w*a[i+j+k]%mod;
a[i+j]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
}
}
}
if (id==-1) reverse(a+1,a+n);
}
void init()
{
mi[0]=1; mul[0]=1;
for (int i=1;i<=n;i++) mi[i]=mi[i-1]*2ll%mod,mul[i]=mul[i-1]*(LL)i%mod;
inv[1]=1;
for (int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
invmul[0]=1;
for (int i=1;i<=n;i++) invmul[i]=invmul[i-1]*inv[i]%mod;
a[0]=b[0]=1;
for (int i=1;i<=fn;i++)
{
a[i]=invmul[i];
if (i&1) a[i]=-a[i];
if (i==1) b[i]=fn+1;
else b[i]=invmul[i]*inv[i-1]%mod*(ksm(i,fn+1)-1)%mod;
}
}
int main()
{
scanf("%d",&fn);int L=0;
for (n=1;n<=fn*2;n<<=1) L++;
for (int i=0;i<n;i++)
r[i]=(r[i>>1]>>1) | ((i&1)<<L-1);
init();
NTT(a,1); NTT(b,1);
for (int i=0;i<n;i++) a[i]=a[i]*b[i]%mod;
NTT(a,-1);
for (int i=0;i<=fn;i++)
{
LL t=mi[i]*mul[i]%mod*a[i]%mod*inv[n]%mod;//别忘了/n
ans=(ans+t)%mod;
}
printf("%lld",(ans+mod)%mod);
}
普及向:
NTT是什么呀
这里给出几组常用模数吧
p c k g
104857601 25 22 3
998244353 119 23 3
1004535809 479 21 3
事实上会出现的只有g,这里的g是模数p的原根,求原根的话,枚举2~p,如果到p-1之前ksm(i,p-x)都不是1,说明i是原根