题解:P14364 [CSP-S 2025] 员工招聘 / employ(民间数据)

· · 题解

大体思路:

显然是 DP,把 c_i 排序后,状态大概就是 s 一维,c 一维,录用了多少人一维。

贡献延迟计算。

具体思路:

先设 f_{i, j} 表示前 i 个人,录用了 j 个人,我们令 d = i-j(即耐心的阈值)。

显然转移不了,原因是不知道还剩哪些 c 可以用,哪些不能用。

考虑怎么记:

分析一下转移时的限制:

发现直接转移的主要问题在于当 d\leftarrow d+1 时,c = d+1 的部分的数量不好计算。

因此,如果每次都把 i 的贡献直接钦定好在上述情况下显然是不行的。

考虑贡献延迟计算:

但这样转移非常复杂,考虑有没有简洁一点的做法:

考虑转移:

统计答案:

Code:

#include<bits/stdc++.h>
using u8 = uint8_t; using u16 = uint16_t; using u32 = uint32_t; using u64 = uint64_t; using i8 = int8_t; using i16 = int16_t; using i32 = int32_t; using i64 = int64_t;
#define ll long long
using namespace std;

const int Maxn = 505;
const ll MOD = 998244353;

namespace Josh_zmf {

    int N, M, all[Maxn], f[Maxn][Maxn][Maxn]; string s; ll fac[Maxn];

    inline int main() {
        cin>> N>> M>> s, s = ' ' + s;
        for(int i=1, x; i<=N; i++)  cin>> x, all[x]++;
        for(int i=1; i<=N; i++) all[i] += all[i-1];
        f[0][0][0] = 1;
        for(int i=0; i<N; i++) {
            for(int j=0; j<=i; j++) {
                for(int k=0; k<=i; k++) {
                    if(s[i+1] == '0') {
                        f[i+1][j][k] = f[i][j][k];
                    } else {
                        f[i+1][j+1][k] = (f[i+1][j+1][k] + f[i][j][k]) %MOD;
                        if(all[i-j]-k > 0) {
                            f[i+1][j+1][k+1] = (f[i+1][j+1][k+1] + -1ll*f[i][j][k]*(all[i-j]-k)) %MOD;
                            f[i+1][j][k+1] = (f[i+1][j][k+1] + 1ll*f[i][j][k]*(all[i-j]-k)) %MOD;
                        }
                    }
                }
            }
        }
        fac[0] = 1;
        for(int i=1; i<=N; i++) fac[i] = fac[i-1]*i %MOD;
        ll ans = 0;
        for(int j=M; j<=N; j++) {
            for(int k=0; k<=N; k++) ans += f[N][j][k]*fac[N-k] %MOD;
        }
        cout<< (ans%MOD+MOD)%MOD<< '\n';
        return 0;
    }

} bool ED;

signed main() {
#if defined(ONLINE_JUDGE) && ONLINE_JUDGE == 1

#elif defined(Debugging)
    freopen("../__IO__/NAME.in", "r", stdin);
#elif !defined(LOCAL)
    freopen("NAME.in", "r", stdin);
    freopen("NAME.out", "w", stdout);
#else
    // freopen("../__IO__/NAME.in", "r", stdin);
    // freopen("../__IO__/NAME.out", "w", stdout);
#endif
    int st = clock(); Josh_zmf::main();
#ifndef Debugging
    cerr<< "time:: "<< clock()-st<< "ms\n";
    cerr<< "Static Memory:: "<< (int)(abs(&ST-&ED)/1024./1024)<< "MB\n";
#endif
    return 0;
}