[CSP-S 2025] 员工招聘题解
P14364 [CSP-S 2025] 员工招聘 / employ(民间数据)
题目背景
由于评测机性能差异,本题时限提升 1 秒。
测试数据未经过检验,可能存在问题,或者可能存在错误做法获得较高分数,仅供参考。
- 2025.11.02 11:21 民间数据更新:对特殊性质 A 的数据点做了修改。
题目描述
小 Z 和小 H 想要合伙开一家公司,共有 n n n 人前来应聘,编号为 1 ∼ n 1 \sim n 1∼n。小 Z 和小 H 希望录用至少 m m m 人。
小 H 是面试官,将在接下来 n n n 天每天面试一个人。小 Z 负责决定应聘人前来面试的顺序。具体地,小 Z 可以选择一个 1 ∼ n 1 \sim n 1∼n 的排列 p p p,然后在第 i i i ( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n) 天通知编号为 p i p_i pi 的人前来面试。
小 H 准备了 n n n 套难度不一的面试题。由于 n n n 个前来应聘的人水平大致相同,因此对于同一套题,所有人的作答结果是一致的。具体地,第 i i i ( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n) 天的面试题的难度为 s i ∈ { 0 , 1 } s_i \in \{0,1\} si∈{0,1},其中 s i = 0 s_i = 0 si=0 表示这套题的难度较高,没有人能够做出; s i = 1 s_i = 1 si=1 表示这套题的难度较低,所有人都能做出。小 H 会根据面试者的作答结果决定是否录用,即如果面试者没有做出面试题,则会拒绝,否则会录用。
然而,每个人的耐心都有一定的上限,如果在他面试之前未录用的人数过多,则他会直接放弃参加面试。具体地,编号为 i i i ( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n) 的人的耐心上限可以用非负整数 c i c_i ci 描述,若在他之前已经有不少于 c i c_i ci 人被拒绝或放弃参加面试,则他也将放弃参加面试。
小 Z 想知道一共有多少种面试的顺序 p p p 能够让他们录用至少 m m m 人。你需要帮助小 Z 求出,能够录用至少 m m m 人的排列 p p p 的数量。由于答案可能较大,你只需要求出答案对 998 244 353 998\,244\,353 998244353 取模后的结果。
输入格式
输入的第一行包含两个正整数 n , m n, m n,m,分别表示前来应聘的人数和希望录用的人数。
输入的第二行包含一个长度为 n n n 的字符串 s 1 … s n s_1 \dots s_n s1…sn,表示每一天的面试题的难度。
输入的第三行包含 n n n 个非负整数 c 1 , c 2 , … , c n c_1, c_2, \dots, c_n c1,c2,…,cn,表示每个人的耐心上限。
输出格式
输出一行一个非负整数,表示能够录用至少 m m m 人的排列 p p p 的数量对 998 244 353 998\,244\,353 998244353 取模后的结果。
输入输出样例 #1
输入 #1
3 2
101
1 1 2
输出 #1
2
输入输出样例 #2
输入 #2
10 5
1101111011
6 0 4 2 1 2 5 4 3 3
输出 #2
2204128
说明/提示
【样例 1 解释】
共有以下 2 种面试的顺序 p p p 能够让小 Z 和小 H 录用至少 2 人:
- p = [ 1 , 2 , 3 ] p = [1,2,3] p=[1,2,3], 依次录用编号为 1 的人和编号为 3 的人;
- p = [ 2 , 1 , 3 ] p = [2,1,3] p=[2,1,3], 依次录用编号为 2 的人和编号为 3 的人。
【样例 3】
见选手目录下的 employ/employ3.in \textbf{\textit{employ/employ3.in}} employ/employ3.in 与 employ/employ3.ans \textbf{\textit{employ/employ3.ans}} employ/employ3.ans。
该样例满足测试点 6 ~ 8 的约束条件。
【样例 4】
见选手目录下的 employ/employ4.in \textbf{\textit{employ/employ4.in}} employ/employ4.in 与 employ/employ4.ans \textbf{\textit{employ/employ4.ans}} employ/employ4.ans。
该样例满足测试点 12 ~ 14 的约束条件。
【样例 5】
见选手目录下的 employ/employ5.in \textbf{\textit{employ/employ5.in}} employ/employ5.in 与 employ/employ5.ans \textbf{\textit{employ/employ5.ans}} employ/employ5.ans。
该样例满足测试点 18 ~ 21 的约束条件。
【数据范围】
对于所有测试数据,保证:
- 1 ≤ m ≤ n ≤ 500 1 \leq m \leq n \leq 500 1≤m≤n≤500;
- 对于所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,均有 s i ∈ { 0 , 1 } s_i \in \{0,1\} si∈{0,1};
- 对于所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,均有 0 ≤ c i ≤ n 0 \leq c_i \leq n 0≤ci≤n。
::cute-table{tuack}
| 测试点编号 | n ≤ n \leq n≤ | m m m | 特殊性质 |
|---|---|---|---|
| 1 , 2 1,2 1,2 | 10 10 10 | ≤ n \leq n ≤n | 无 |
| 3 ∼ 5 3 \sim 5 3∼5 | 18 18 18 | ^ | ^ |
| 6 ∼ 8 6 \sim 8 6∼8 | 1 0 2 10^2 102 | ^ | A |
| 9 ∼ 11 9 \sim 11 9∼11 | ^ | ^ | 无 |
| 12 ∼ 14 12 \sim 14 12∼14 | 500 500 500 | = 1 =1 =1 | ^ |
| 15 15 15 | ^ | = n =n =n | ^ |
| 16 , 17 16,17 16,17 | ^ | ≤ n \leq n ≤n | A |
| 18 ∼ 21 18 \sim 21 18∼21 | ^ | ^ | B |
| 22 ∼ 25 22 \sim 25 22∼25 | ^ | ^ | 无 |
特殊性质 A: 对于所有 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,均有 s i = 1 s_i = 1 si=1。
特殊性质 B: 在 s 1 , s 2 , … , s n s_1, s_2, \dots, s_n s1,s2,…,sn 中最多只有 18 个取值为 1,即 ∑ i = 1 n s i ≤ 18 \sum_{i=1}^{n} s_i \leq 18 ∑i=1nsi≤18。
思路
DP即可,首先容易想到暴力状态压缩DP。
暴力代码
#include<bits/stdc++.h>
using namespace std;
long long n,m,c[100005],mod=998244353,f[20][300005],rm[200005],d,df=0,op=0;
char s[100005];
bool bo[100005];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s[i];
}
for(int i=1;i<=n;i++){
cin>>c[i];
}
rm[0]=1;
for(int i=1;i<=18;i++){
rm[i]=rm[i-1]*2;
}
if(n<=18){
f[0][0]=1;
d=pow(2,n)-1;
for(int i=0;i<=n-1;i++){
for(int j=0,k;j<=d;j++){
//cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
k=j;
df=0;
for(int o=0;o<=n-1;o++){
if(k%2==1){
bo[o]=1;
df++;
}
else{
bo[o]=0;
}
k/=2;
}
for(int o=0;o<=n-1;o++){
if(bo[o]==0){
if(s[df+1]=='0'){
f[i][j+rm[o]]=(f[i][j+rm[o]]+f[i][j])%mod;
}
else{
if(c[o+1]<=df-i){
f[i][j+rm[o]]=(f[i][j+rm[o]]+f[i][j])%mod;
}
else{
f[i+1][j+rm[o]]=(f[i+1][j+rm[o]]+f[i][j])%mod;
}
}
}
}
}
}
for(int i=m;i<=n;i++){
op=(op+f[i][d])%mod;
}
cout<<op<<endl;
}
else{
cout<<0<<endl;
}
return 0;
}
显然过不了题目,所以考虑优化。以 f i , j , k f_{i,j,k} fi,j,k表示至第i人,j个人失败,k个耐心不大于j的人,参照了出题人题解。
代码见下
#include<bits/stdc++.h>
using namespace std;
const long long mod=998244353;
long long n,m,c[100005],f[505][505][505],b[505],d[505],cc[505][505],jx[100005],op=0;
char s[100005];
bool bo[100005];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>s[i];
}
for(int i=1;i<=n;i++){
cin>>c[i];
b[c[i]]++;
}
d[0]=b[0];
for(int i=1;i<=n;i++){
d[i]=d[i-1]+b[i];
}
cc[0][0]=jx[0]=1;
for(int i=1;i<=n;i++){
cc[i][0]=1;
jx[i]=jx[i-1]*i%mod;
for(int j=1;j<=i;j++){
cc[i][j]=(cc[i-1][j]+cc[i-1][j-1])%mod;
}
}
f[0][0][0]=1;
for(int i=0;i<=n-1;i++){
if(s[i+1]=='1'){
for(int j=0;j<=i;j++){
for(int k=0;k<=d[j]&&k<=i;k++){
if(n-d[j]>=i-k+1){
f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;
}
for(int o=0;o<=b[j+1]&&o<=i-k;o++){
f[i+1][j+1][k+o+1]=(f[i+1][j+1][k+o+1]+f[i][j][k]*(d[j]-k)%mod*cc[b[j+1]][o]%mod*cc[i-k][o]%mod*jx[o]%mod)%mod;
}
}
}
}
else{
for(int j=0;j<=i;j++){
for(int k=0;k<=d[j]&&k<=i;k++){
for(int o=0;o<=b[j+1]&&o<=i-k;o++){
if(n-d[j+1]>=i-k-o+1){
f[i+1][j+1][k+o]=(f[i+1][j+1][k+o]+f[i][j][k]%mod*cc[b[j+1]][o]%mod*cc[i-k][o]%mod*jx[o]%mod)%mod;
}
f[i+1][j+1][k+o+1]=(f[i+1][j+1][k+o+1]+f[i][j][k]*(d[j+1]-k-o)%mod*cc[b[j+1]][o]%mod*cc[i-k][o]%mod*jx[o]%mod)%mod;
}
}
}
}
}
for(int i=0;i<=n-m;i++){
op=(op+f[n][i][d[i]]*jx[n-d[i]]%mod)%mod;
}
cout<<op<<endl;
return 0;
}

浙公网安备 33010602011771号