1 条题解

  • 0
    @ 2026-8-31 1:17:06

    upd:感谢 Jorisy 指出一处 typo,已修复。

    【题意】

    小 Z 和小 H 想要合伙开一家公司,共有 nn 人前来应聘,编号为 1n1 \sim n。小 Z 和小 H 希望录用至少 mm 人。

    小 H 是面试官,将在接下来 nn 天每天面试一个人。小 Z 负责决定应聘人前来面试的顺序。具体地,小 Z 可以选择一个 1n1 \sim n 的排列 pp,然后在第 ii (1in1 \leq i \leq n) 天通知编号为 pip_i 的人前来面试。

    小 H 准备了 nn 套难度不一的面试题。由于 nn 个前来应聘的人水平大致相同,因此对于同一套题,所有人的作答结果是一致的。具体地,第 ii (1in1 \leq i \leq n) 天的面试题的难度为 si{0,1}s_i \in \{0,1\},其中 si=0s_i = 0 表示这套题的难度较高,没有人能够做出;si=1s_i = 1 表示这套题的难度较低,所有人都能做出。小 H 会根据面试者的作答结果决定是否录用,即如果面试者没有做出面试题,则会拒绝,否则会录用。

    然而,每个人的耐心都有一定的上限,如果在他面试之前未录用的人数过多,则他会直接放弃参加面试。具体地,编号为 ii (1in1 \leq i \leq n) 的人的耐心上限可以用非负整数 cic_i 描述,若在他之前已经有不少于 cic_i 人被拒绝或放弃参加面试,则他也将放弃参加面试。

    小 Z 想知道一共有多少种面试的顺序 pp 能够让他们录用至少 mm 人。你需要帮助小 Z 求出,能够录用至少 mm 人的排列 pp 的数量。由于答案可能较大,你只需要求出答案对 998244353998\,244\,353 取模后的结果。

    1mn5001 \leq m \leq n \leq 500.

    【题解】

    哎。这个t4不是比【最古的遗迹】还简单的同类题???那我场上不做这个T4一直调那个弱智T3不是纯糖???

    把计数排列看作天和人的匹配。按值域考虑每个人和哪个匹配。大致为 dp(i,j)dp(i,j) 表示 cic\le i 的人里有 jj 个面试失败的方案数。

    然后就发现当决策一个人面试失败的时候并不只涉及 cc 比它小的人,因为可以让一个 cc 大的人遇到 00,所以还要额外记录后面有多少个人面试失败了。

    为了避免记录每个人的状态,我们要考虑什么情况下两个不同的人就本质相同了。

    (i,cpi)(i,c_{p_i}) 在坐标系上画成柱状图,画一条左下到右上的折线表示每一天的失败人数变化。这样就容易看出因为折线是单调向上的,所以在某次折线达到 xx 的高度后,之后耐心值 x\le x 的人都不可能被录取,而 >x>x 的人只要放在 11 的位置就一定会被录取。

    所以考虑把人分作耐心值 x,>x\le x,>x 考虑。因为 xx 是单调上升的,所以过程中会有一些 >x>x 的人进入 x\le x,但是 x\le x 的永远会 x\le x。所以 "x\le x 的人" 是确定的部分,">x>x 的人" 是不确定的部分。用【P7213 最古の遺跡 3】的经典延迟确定的 trick,考虑设 dp(i,j,k)dp(i,j,k) 表示决策前 ii 天的安排、有 jj 个人失败、有 kk 个位置的人耐心值 >j>j(等待后面决策),在 dpdp 里只决策前 ii 天耐心值 j\le j 的方案数。

    使用刷表法转移。考虑第 i+1i+1 天的人是要失败还是要通过。记 cnticnt_i 表示耐心值为 ii 的人数,scsccntcnt 的前缀和。

    • si+1=0s_{i+1}=0

      必须失败。分类讨论 cpi+1c_{p_{i+1}}j+1j+1 的大小关系,并把 kk 个人里 =j+1=j+1 的纳入考虑。

      • cpi+1>j+1c_{p_{i+1}}>j+1

        $$\sum_{w=0}^k\binom{k}{w}\binom{cnt_{j+1}}{w}w!dp(i,j,k)\rightarrow dp(i+1,j+1,k-w+1)$$
      • cpi+1j+1c_{p_{i+1}}\le j+1

        $$\sum_{w=0}^k\binom{k}{w}\binom{cnt_{j+1}}{w}w!(sc_{j+1}-(i-(k-w))dp(i,j,k)\rightarrow dp(i+1,j+1,k-w)$$
    • si+1=1s_{i+1}=1

      • cpi+1>jc_{p_{i+1}}>j,此时会录取,jj 不变。

        dp(i,j,k)dp(i+1,j,k+1)dp(i,j,k)\rightarrow dp(i+1,j,k+1)
      • cpi+1jc_{p_{i+1}}\le j,此时会放弃,jj 加一。

        $$\sum_{w=0}^k\binom{k}{w}\binom{cnt_{j+1}}{w}w!(sc_{j}-(i-k))dp(i,j,k)\rightarrow dp(i+1,j+1,k-w)$$

    虽然看起来要枚举 wwO(n4)O(n^4) 的,但因为总人数 O(n)O(n),所以 ww 一共只能枚举 nn 次。故总复杂度是 O(n3)O(n^3) 的。

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int N = 505, mod = 998244353;
    
    void add(ll &x, ll y) {
    	x += y;
    	if (x >= mod)
    		x -= mod;
    }
    
    int n, m;
    int s[N];
    
    ll fpow(ll a, ll b = mod - 2, ll p = mod) {
    	ll mul = 1;
    	while (b) {
    		if (b & 1)
    			mul = mul * a % p;
    		a = a * a % p;
    		b >>= 1;
    	}
    	return mul;
    }
    ll fac[N], ifac[N];
    
    ll C(ll n, ll m) {
    	return m < 0 || m > n ? 0 : fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    }
    
    ll dp[N][N][N] = {{{}}};
    
    int cnt[N], sc[N];
    
    int main() {
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++)
    		scanf("%1d", &s[i]);
    	for (int i = 1, x; i <= n; i++) {
    		cin >> x;
    		cnt[x]++;
    	}
    	sc[0] = cnt[0];
    	for (int i = 1; i <= n; i++)
    		sc[i] = sc[i - 1] + cnt[i];
    	
    	fac[0] = 1;
    	for (int i = 1; i <= n; i++)
    		fac[i] = fac[i - 1] * i % mod;
    	ifac[n] = fpow(fac[n]);
    	for (int i = n - 1; i >= 0; i--)
    		ifac[i] = ifac[i + 1] * (i + 1) % mod;
    	
    	dp[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 (dp[i][j][k]) {
    					if (s[i + 1] == 0) {
    						for (int w = 0; w <= k && w <= cnt[j + 1]; w++)
    							add(dp[i + 1][j + 1][k - w + 1], 
    								C(cnt[j + 1], w) * fac[w] % mod * C(k, w) % mod * dp[i][j][k] % mod);
    						for (int w = 0; w <= k && w <= cnt[j + 1]; w++)
    							add(dp[i + 1][j + 1][k - w],
    								C(cnt[j + 1], w) * fac[w] % mod * C(k, w) % mod * (sc[j + 1] - (i - (k - w))) % mod * dp[i][j][k] % mod);
    					}
    					else {
    						for (int w = 0; w <= k && w <= cnt[j + 1]; w++)
    							add(dp[i + 1][j + 1][k - w],
    								C(cnt[j + 1], w) * fac[w] % mod * C(k, w) % mod * (sc[j] - (i - k)) % mod * dp[i][j][k] % mod);
    						add(dp[i + 1][j][k + 1], dp[i][j][k]);
    					}
    				}
    	
    	ll ans = 0;
    	for (int j = 0; j <= n - m; j++)
    		add(ans, dp[n][j][n - sc[j]] * fac[n - sc[j]] % mod);
    	cout << ans << '\n';
    	return 0;
    }
    
    • 1

    信息

    ID
    1392
    时间
    1000ms
    内存
    1024MiB
    难度
    9
    标签
    递交数
    44
    已通过
    2
    上传者