CF1515E 题解
dangbowen1008 · · 题解
一个
结论先行:
观察最终情况。可以发现其由若干个由手动开启的电脑的连续的块组成。而且这些块之间必须由恰好一台自动开启的电脑隔开。
也就是:
一段手动开启 + 一个自动开启 + 一段手动开启 + ⋯ + 一个自动开启 + 一段手动开启
假设有
则自动开启的电脑数量为
我们现在有
引入经典结论:
将
A 个不同的元素放入k 个有序且非空的集合中,方案数等于k! \cdot S(A,k) ,其中S(n,m) 是第二类斯特林数。
这便解决完了不同块之间操作顺序的分配的方案数。
我们来看块内的。
对于一个长度为
注意这里不是
那我们倒着想。这个块内最后被开启的电脑一定位于这个块的两端(一共两种可能)。将其剥离之后,剩下的
则合法开启一个块的顺序有
根据乘法原理,这
我们可以将其与前面的操作分配方案数直接相乘,得到对于固定
分析
代入
预处理第二类斯特林数即可
#include <iostream>
using namespace std;
const int N = 405;
int n, M, ans;
int S[N][N], fac[N], p2[N];
int main() {
cin >> n >> M;
S[0][0] = fac[0] = p2[0] = 1;
for (int i = 1; i <= n; i++) {
fac[i] = 1ll * fac[i - 1] * i % M;
p2[i] = 2ll * p2[i - 1] % M;
for (int j = 1; j <= i; j++)
S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % M;
}
for (int k = 1; k <= (n + 1) / 2; k++) {
int A = n - k + 1;
ans = (ans + 1ll * fac[k] * S[A][k] % M * p2[A - k]) % M;
}
cout << ans;
return 0;
}
鉴于最终的答案式子非常的优美简洁,我猜测它可以在