CodeForces 1515E Phoenix and Computers
思路
引理:\(n\) 台电脑全部手动打开的方案数为 \(2^{n-1}\)。
证明:设第一台打开的电脑是第 \(x\) 台。则 \(x+2\) 一定在 \(x+1\) 后打开,\(x+3\) 一定在 \(x+2\) 后打开,……,\(n\) 一定在 \(n-1\) 后打开。同理 \(x-2\) 一定在 \(x-1\) 后打开,\(x-3\) 一定在 \(x-2\) 后打开,……,\(1\) 一定在 \(2\) 后打开。\([x+1,n]\) 和 \([1,x-1]\) 这两段相对顺序决定了,绝对顺序就穿插合并。想象有 \(n-1\) 个空,那么要选 \(x-1\) 个空供 \([1,x-1]\) 放,剩下 \(n-x\) 个空供 \([x+1,n]\) 放,方案数为 \(C_{n-1}^{x-1}\)。因此 \(n\) 台电脑全部手动打开的方案数为 \(\sum\limits_{x=1}^n C_{n-1}^{x-1} = 2^{n-1}\)。
然后 dp。设 \(f_{i,j}\) 表示前 \(i\) 台电脑有 \(j\) 台是自动打开的方案数。有:
\[f_{i,0} = 2^{i-1}
\]
\[f_{i,j} = \sum\limits_{k=2}^{i-1} f_{k-1,j-1} \times 2^{i-k-1} \times C_{i-j}^{i-k}
\]
相当于枚举上一台自动打开的电脑 \(k\),则 \([k+1,i]\) 内的电脑都要手动打开,根据引理,此方案数为 \(2^{i-k-1}\)。总共需要手动打开的电脑有 \(i-j\) 台,\([k,i]\) 这一段内需要手动打开的电脑有 \(i-k\) 台,若这 \(i-k\) 台电脑的相对打开顺序已经确定了,将 \(i-k\) 台电脑插入 \(i-j\) 台电脑的方案数为 \(C_{i-j}^{i-k}\)。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 410;
ll n, mod, ifac[maxn], fac[maxn], f[maxn][maxn], pw[maxn];
ll qpow(ll b, ll p) {
ll res = 1;
while (p) {
if (p & 1) {
res = res * b % mod;
}
b = b * b % mod;
p >>= 1;
}
return res;
}
ll C(ll n, ll m) {
if (n < m || n < 0 || m < 0) {
return 0;
} else {
return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
}
void solve() {
scanf("%lld%lld", &n, &mod);
fac[0] = 1;
for (int i = 1; i <= n; ++i) {
fac[i] = fac[i - 1] * i % mod;
}
ifac[n] = qpow(fac[n], mod - 2);
for (int i = n - 1; ~i; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
pw[0] = 1;
for (int i = 1; i <= n; ++i) {
pw[i] = pw[i - 1] * 2 % mod;
}
for (int i = 1; i <= n; ++i) {
f[i][0] = pw[i - 1];
for (int j = 1; j <= (i - 1) / 2; ++j) {
for (int k = 2; k < i; ++k) {
f[i][j] = (f[i][j] + f[k - 1][j - 1] * pw[i - k - 1] % mod * C(i - j, i - k) % mod) % mod;
}
}
}
ll ans = 0;
for (int i = 0; i <= n; ++i) {
ans = (ans + f[n][i]) % mod;
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号