专栏文章
P14364 [CSP-S 2025] 员工招聘 / employ
P14364题解参与者 10已保存评论 14
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 14 条
- 当前快照
- 1 份
- 快照标识符
- @minf23j2
- 此快照首次捕获于
- 2025/12/02 01:21 3 个月前
- 此快照最后确认于
- 2025/12/02 01:21 3 个月前
我场上最后 30min 想到了的!!!但是一堆分讨没时间了/ll
思路:
你发现排列的计数,一般状态是重点;这题对排列的限制在 这里,于是考虑把 这个东西压进状态里。
于是想到 表示考虑前 天,前面有 个人 fail 了,然后其中有 个人 的方案数(此时这些人具体是谁是没有必要的,因为只要他的 就不会造成影响),于是前面 天选了 个 的,进行分讨(这里设 表示 等于 的人的数量, 表示 小于等于 的人的数量):
- 若 :
-
此时若放一个 的人来,方案数是 ,它会 fail,那么会使 ,然后 的变化不太清楚,所以考虑枚举前面恰好选了 个 是 的:
-
否则放一个 的人来,于是 不变, 加一:
- 若 :
-
此时随便放一个都是 fail,所以 ,同时也要枚举前面恰好选了 个 是 的,于是考虑若放 进来,方案数是 :
-
若是放 进来,则 要多加 :
你发现所有枚举的 ,于是时间复杂度是 的。
完整代码:
CPP#include<bits/stdc++.h>
#define ls(k) k << 1
#define rs(k) k << 1 | 1
#define fi first
#define se second
#define popcnt(x) __builtin_popcount(x)
#define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout);
using namespace std;
typedef __int128 __;
typedef long double lb;
typedef double db;
typedef unsigned long long ull;
typedef long long ll;
bool Begin;
const int N = 505, mod = 998244353;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int n, m, ans;
int dp[N][N][N], w[N], s[N], C[N][N], fac[N];
char op[N];
int c[N];
inline void getadd(int &x, int y){
x = (x + y >= mod) ? (x + y - mod) : (x + y);
}
inline int add(int x, int y){
return (x + y >= mod) ? (x + y - mod) : (x + y);
}
bool End;
int main(){
n = read(), m = read();
scanf("%s", op + 1);
for(int i = 1; i <= n; ++i){
c[i] = read();
++w[c[i]];
}
fac[0] = 1;
s[0] = w[0];
for(int i = 1; i <= n; ++i){
s[i] = s[i - 1] + w[i];
fac[i] = 1ll * fac[i - 1] * i % mod;
// cerr << s[i] << ' ';
}
for(int i = 0; i <= n; ++i){
C[i][0] = 1;
for(int j = 1; j <= i; ++j)
C[i][j] = add(C[i - 1][j], C[i - 1][j - 1]);
}
dp[0][0][0] = 1;
for(int i = 1; i <= n; ++i){
for(int j = 0; j <= i - 1; ++j){
for(int k = 0; k <= i - 1; ++k){
if(!dp[i - 1][j][k])
continue;
// cerr << "Yes\n" << ' ' << i - 1 << ' ' << j << ' ' << k << ' ' << dp[i - 1][j][k] << '\n';
if(op[i] == '1'){
// if(s[j] != n)
// cerr << i << ' ' << j << ' ' << k + 1 << '\n';
getadd(dp[i][j][k + 1], dp[i - 1][j][k]);
if(s[j] - i + k + 1 < 0)
continue;
for(int l = 0; l <= min(k, w[j + 1]); ++l)
getadd(dp[i][j + 1][k - l], 1ll * dp[i - 1][j][k] * (s[j] - i + k + 1) % mod * C[w[j + 1]][l] % mod * C[k][l] % mod * fac[l] % mod);
}
else{
for(int l = 0; l <= min(k, w[j + 1]); ++l){
// if(s[j + 1] != n)
getadd(dp[i][j + 1][k - l + 1], 1ll * dp[i - 1][j][k] * C[w[j + 1]][l] % mod * C[k][l] % mod * fac[l] % mod);
if(s[j + 1] - i + k + 1 - l > 0)
getadd(dp[i][j + 1][k - l], 1ll * dp[i - 1][j][k] * (s[j + 1] - i + k + 1 - l) % mod * C[w[j + 1]][l] % mod * C[k][l] % mod * fac[l] % mod);
}
}
}
}
}
for(int i = 0; i <= n - m; ++i)
getadd(ans, 1ll * fac[n - s[i]] * dp[n][i][n - s[i]] % mod);
write(ans);
//chrr << '\n' << abs(&Bhgin - &End) / 1048576 << "MB";
return 0;
}
相关推荐
评论
共 14 条评论,欢迎与作者交流。
正在加载评论...