CF1349F1 Slime and Sequences (Easy Version)
CF1349F1 Slime and Sequences (Easy Version)
好神仙啊。。。
我们可以构造出排列和好序列的双射,然后就做完了。
看样例发现输出总和是 \(n\cdot n!\) 就可以往这个结论猜 ,然而我太菜了,没构造出来/kk
把排列划分为若干下降的子区间,第 \(i\) 段子区间赋值为 \(i\) ,这样得到的序列一定可行。
比如
\[\mathrm{7,5,4,6,1,3,2}\to\mathrm{(7,5,4),(6,1),(3,2)}\to 2,3,3,1,1,2,1
\]
从一个好区间也可以还原出唯一确定的排列,所以就双射了。
从原本的数好序列可以转化为:数所有排列第 \(k\) 段长度总和。
考虑计算排列里位置 \(i\) 对于答案第 \(k\) 项的贡献。
那么 \(i\) 之前就有 \(k-1\) 个升高,方案数是 \(\left<\begin{matrix}i\\k-1\end{matrix}\right>\) (欧拉数相关内容可以看 多项式笔记(二))
\(i\) 之后随便排,是 \((n-i)!\) 。
同时我们还要选择 \(i\) 个数放到前面 \(i\) 项,是 \(\dbinom{n}{i}\) 。
整合起来就是
\[ans_k=\sum_{i=1}^{n}\left<\begin{matrix}i\\k-1\end{matrix}\right>(n-i)!\binom{n}{i}
\]
\(O(n^2)\) 递推欧拉数然后直接算就好了。
#define mod 998244353
inline int qpow(int n,int k){int res=1;for(;k;k>>=1,n=1ll*n*n%mod)if(k&1)res=1ll*n*res%mod;return res;}
const int N=5005;
int o[N][N],n,ans[N],fac[N],ifc[N];
inline int comb(int n,int m){return n<m?0:1ll*fac[n]*ifc[m]%mod*ifc[n-m]%mod;}
signed main(){
n=read();
o[0][0]=1;
rep(i,1,n)rep(j,0,i-1){
o[i][j]=1ll*o[i-1][j]*(j+1)%mod;
if(j>0)o[i][j]=(1ll*o[i-1][j-1]*(i-j)%mod+o[i][j])%mod;
}
fac[0]=1;rep(i,1,n)fac[i]=1ll*fac[i-1]*i%mod;
ifc[n]=qpow(fac[n],mod-2);per(i,n-1,0)ifc[i]=1ll*(i+1)*ifc[i+1]%mod;
rep(k,1,n)rep(i,1,n)ans[k]=(ans[k]+1ll*fac[n-i]*o[i][k-1]%mod*comb(n,i)%mod)%mod;
rep(i,1,n)printf("%d%c",ans[i]," \n"[i==n]);
return 0;
}
路漫漫其修远兮,吾将上下而求索