Link.
Description.
有 \(n\) 个球,构造若干组满足:
- 每组至多两个球至少一个球
- 不存在一个球出现在多个组
- 如果一组有两个球,这两个球相邻
问为 \(k\in[0,M]\) 的方案数。
Solution.
首先,有个显然的 dp 为 \(dp_{i,j}=dp_{i-1,j}+dp_{i-1,j-1}+dp_{i-2,j-1}\)。
可以考虑成有一个网格每次可以走 \(\vec v=(1,0),(2,1),(1,1)\),求方案数。
考虑枚举 \((2,1)\) 个数为 \(k\),则有答案为
\[\begin{aligned}
&=\sum_{k=0}^m\dbinom{n-2k}{m-k}\dbinom{n-k}{k}\\
&=\sum_{k=0}^m\dbinom{n-k}{m}\dbinom{m}{k}
\end{aligned}
\]
接下来参考了这篇题解
组合意义是先从前 \(m\) 个选出了若干个,然后从剩下的里再选出 \(m\) 个的方案数。
可以考虑容斥,钦定 \(k\) 个必须重复选,剩下随意。
方案数是 \(\dbinom{m}{k}2^{m-k}\dbinom{n-k}{m-k}\),分别为:前 \(m\) 个里钦定 \(k\) 个重复,前 \(m\) 个里除了 \(k\) 个之外随意,剩下里选出不重复的。
\[\therefore\begin{aligned}
&=\sum_{k=0}^m(-1)^k\dbinom{m}{k}\dbinom{n-k}{m-k}2^{m-k}\\
&=m!n^{\underline{m}}\sum_{k=0}^m\frac{(-1)^k}{k!n^{\underline k}}\frac{2^{m-k}}{(m-k)!^2}
\end{aligned}
\]
Coding.
点击查看代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int P=998244353,N=32768;
int fc[N],fi[N],iv[N];//dbinit{{{
inline int ksm(int x,int q=P-2) {int r=1;for(;q;q>>=1,x=1ll*x*x%P) if(q&1) r=1ll*r*x%P;return r;}
inline void dbinit(int n=N-1)
{
fc[0]=1;for(int i=1;i<=n;i++) fc[i]=1ll*fc[i-1]*i%P;
iv[1]=1;for(int i=2;i<=n;i++) iv[i]=1ll*iv[P%i]*(P-P/i)%P;
fi[0]=1;for(int i=1;i<=n;i++) fi[i]=1ll*fi[i-1]*iv[i]%P;
}
inline int C(int n,int m) {return n<0||m<0||n<m?0:1ll*fc[n]*fi[m]%P*fi[n-m]%P;}//}}}
namespace poly//{{{
{
const int P=998244353,G=3,L=119,Z=23;int rev[N],g[Z+5][2];
inline void init(int T)
{
rev[0]=0;for(int i=1;i<T;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?(T>>1):0);
if(g[Z][0]) return;else g[Z][0]=ksm(G,L),g[Z][1]=ksm(ksm(G),L);
for(int i=Z;i;i--) g[i-1][0]=1ll*g[i][0]*g[i][0]%P,g[i-1][1]=1ll*g[i][1]*g[i][1]%P;
}
#define fst(x) ((x)>=P?(x)-P:(x))
inline void NTT(int T,int *a,int flg)
{
for(int i=0;i<T;i++) if(rev[i]>i) swap(a[i],a[rev[i]]);
for(int d=1,rp=1;d<T;d<<=1,rp++)
for(int i=0,wn=g[rp][flg];i<T;i+=(d<<1))
for(int k=0,w=1;k<d;k++,w=1ll*w*wn%P)
{int x=a[i+k],y=1ll*a[i+k+d]*w%P;a[i+k]=fst(x+y),a[i+k+d]=fst(x-y+P);}
if(flg) {int iv=ksm(T);for(int i=0;i<T;i++) a[i]=1ll*a[i]*iv%P;}
}
}//}}}
int n,K,A[N<<1],B[N<<1];
int main()
{
read(n,K),dbinit();int vl=1,T=1;while(T<=K+K) T<<=1;poly::init(T);
for(int k=0;k<=K;k++)
{
A[k]=1ll*fi[k]*vl%P,A[k]=(k&1?P-A[k]:A[k]);
B[k]=1ll*ksm(2,k)*fi[k]%P*fi[k]%P;
vl=1ll*vl*ksm(n-k)%P;
}
poly::NTT(T,A,0),poly::NTT(T,B,0);for(int i=0;i<T;i++) A[i]=1ll*A[i]*B[i]%P;
poly::NTT(T,A,1),vl=1;for(int i=0;i<T;i++) A[i]=1ll*vl*A[i]%P*fc[i]%P,vl=1ll*vl*(n-i)%P;
for(int i=1;i<=K;i++) printf("%d%c",A[i],i==K?'\n':' ');
return 0;
}