1 条题解
-
0
这个只是暂时保存一下,并不作为题解
题解
- 未录用人数 单调不减。当已有 人未录用时: 的人必放弃, 的人能否录用只取决于 。
- 因此把人分成「」(身份必须当场确定,因为影响结果)和「」(只关心个数,身份可延后确定)。这就是贡献延后计算:过程中 的人不指定是谁,只记占位数 ;当 加一时,把 这批人从 个占位中剥离 个、当场确定身份。
:已面试 人,其中 人未录用,已录用者中恰有 人满足 ,且只计算了 的人的贡献。
辅助:,。
已面试 人中有 未录、 已录;其中 个已录者 ,所以已录者里 的有 人。剩余可选:
- 未选: 人;
- 未选: 人。
若 (必录用):
- 放一个 的人:必录用,,系数 (身份延后):
- 放一个 的人:必放弃,。先剥离 个占位实为 ( 种 ),当前人从 个未选者中挑一个:
若 (必拒绝),:。
- 放 的人:必拒绝,:
- 放 的人:必拒绝,,当前人从 个未选者中挑:
:设有 个人满足他们的 ,从耐心值刚爆()中选 个为 ,从没有确定位置的 个人选 个为 ,则有 种方案数。
答案: 结束时已录的 人全是 ,占位数 ,他们之间还有 种排列未计入:
$$\text{ans}=\sum_{j=0}^{n-m} dp[n][j][n-pre_j]\cdot (n-pre_j)!$$代码
阶乘和组合数预处理一下。
时间复杂度:,空间如果直接转移是 ,会MLE,所以要滚动数组优化,实际空间复杂度:。
// [CSP-S 2025] 员工招聘 #include <iostream> using namespace std; #define MOD 998244353 int n, m, dp[2][505][505], fac[505], comb[505][505], cnt[505], pre[505], ans; char s[505]; int main() { freopen("employ.in", "r", stdin); freopen("employ.out", "w", stdout); cin >> n >> m >> (s + 1); fac[0] = 1; for (int i = 1, c; i <= n; ++i) { cin >> c; fac[i] = 1ll * fac[i - 1] * i % MOD; cnt[c]++; } pre[0] = cnt[0]; for (int i = 1; i <= n; ++i) pre[i] = pre[i - 1] + cnt[i]; for (int i = 0; i <= n; ++i) { comb[i][0] = 1; for (int j = 1; j <= i; ++j) comb[i][j] = (comb[i - 1][j - 1] + comb[i - 1][j]) % MOD; } dp[0][0][0] = 1; for (int i = 0; i < n; ++i) { int cur = i & 1, nxt = cur ^ 1; for (int j = 0; j <= i; ++j) for (int k = 0; k <= i; ++k) dp[nxt][j][k] = 0; for (int j = 0; j <= i; ++j) { for (int k = 0; k <= i; ++k) { if (s[i + 1] == '0') { for (int t = 0; t <= min(cnt[j + 1], k); ++t) { // c > j + 1 int num = 1ll * comb[cnt[j + 1]][t] * fac[t] % MOD * comb[k][t] % MOD; int dp_cur = 1ll * num * dp[cur][j][k] % MOD; dp[nxt][j + 1][k - t + 1] = (dp[nxt][j + 1][k - t + 1] + dp_cur) % MOD; // c <= j + 1 int choose = pre[j + 1] - (i - (k - t)); if (choose > 0) { dp_cur = 1ll * dp_cur * choose % MOD; dp[nxt][j + 1][k - t] = (dp[nxt][j + 1][k - t] + dp_cur) % MOD; } } } else { // c <= j int choose = pre[j] - (i - k); if (choose > 0) { for (int t = 0; t <= min(cnt[j + 1], k); ++t) { int num = 1ll * comb[cnt[j + 1]][t] * comb[k][t] % MOD * fac[t] % MOD; int dp_cur = 1ll * choose * num % MOD * dp[cur][j][k] % MOD; dp[nxt][j + 1][k - t] = (dp[nxt][j + 1][k - t] + dp_cur) % MOD; } } // c > j if (n - pre[j] - k > 0) dp[nxt][j][k + 1] = (dp[nxt][j][k + 1] + dp[cur][j][k]) % MOD; } } } } for (int j = 0; j <= n - m; ++j) ans = (ans + 1ll * dp[n & 1][j][n - pre[j]] * fac[n - pre[j]] % MOD) % MOD; cout << ans << '\n'; return 0; }
- 1
信息
- ID
- 2631
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 8
- 标签
- (无)
- 递交数
- 4
- 已通过
- 4
- 上传者