F - Two Exams
题目概述:
有
n
n
n 个公民,现在对这
n
n
n 个公民分别进行了两次排名,每个城市获得的排名分别为
P
i
P_i
Pi 和
Q
i
Q_i
Qi,现在要在这
n
n
n 个公民中选出
K
K
K 个城市,并且给出以下约束:
- 当选择 x x x 而不选择城市 y y y 时,一定不能有 P x > P y P_x > P_y Px>Py 且 Q x > Q y Q_x > Q_y Qx>Qy
思路:
上述条件是说,如果市民
X
X
X 的两次排名都比市民
Y
Y
Y 要靠前,那么我们选择
Y
Y
Y 之前必须把
X
X
X 选上。
在上述条件中,对于每个市民我们都只有选或不选两个选项,可以看出这是一个有约束的
01
01
01 背包问题,我们现在可以表示的状态有:枚举到了第
i
i
i 个市民,在前
i
i
i 个市民中我们一共选择了
j
j
j 个。
对于每个市民选或者不选的约束,首先,我们将这些市民以
P
i
P_i
Pi 升序排序,这样我们正向枚举时,保证了
P
i
P_i
Pi 是递增的。
然后我们可以单独开一维数组,来记录当前已经选择了的市民中, 最低的
Q
i
Q_i
Qi 是多少。
最终的状态表示:
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k] 前
i
i
i 个人中,选择了
j
j
j 个人,并且当前选择的人中排名最靠后的人为
k
k
k
假设当前已经选择的人中
Q
i
Q_i
Qi 最靠后的排名为
k
k
k ,只有当枚举到的
Q
i
<
k
Q_i < k
Qi<k 时,才可以选择第
i
i
i 个人:
f[i][j + 1][k] += f[i - 1][j][k]
同时也可以不选择第
i
i
i 个人:
f[i][j][k] += f[i - 1][j][k]
但是,如果此时的
Q
i
<
k
Q_i < k
Qi<k ,此时应当更新 我们不能够跳过
Q
i
Q_i
Qi 去选择 第
k
k
k大的值,所以将当前的最靠后排名
k
k
k换为
Q
i
Q_i
Qi 即可.
f[i][j][Q_i] += f[i - 1][j][k]
初始化:
全选只有一种方案: f[n][n][n] = 1
一个不选也只有一种方案 f[0][0][n + 1] = 1
代码:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 310, mod = 998244353;
int f[N][N][N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("D:/Cpp/program/Test.in", "r", stdin);
freopen("D:/Cpp/program/Test.out", "w", stdout);
#endif
int n, K;
cin >> n >> K;
PII a[n + 1];
for(int i = 1; i <= n; i ++) cin >> a[i].first;
for(int i = 1; i <= n; i ++) cin >> a[i].second;
sort(a + 1, a + n + 1);
f[0][0][n + 1] = 1;
f[n][n][n] = 1;
for(int i = 1; i <= n; i ++) {
for(int j = 0; j <= K; j ++) {
for(int k = 0; k <= n + 1; k ++) {
//如果不选择 a[i] 那么a[i].second 一定是大于 k 的,
//如果 小于 k 则需要将结尾为 k 的数换为 a[i].second
f[i][j][min(a[i].second, k)] += f[i - 1][j][k];
f[i][j][min(a[i].second, k)] %= mod;
if(a[i].second < k) {
f[i][j + 1][k] += f[i - 1][j][k];
f[i][j + 1][k] %= mod;
}
}
}
}
int ans = 0;
//如果 K == n 即选择所有人
for(int i = 1; i <= n; i ++) {
// cout << f[n][K][i] << '\n';
ans += f[n][K][i];
ans %= mod;
}
// if(K == n) cout << 1 << '\n';
// else
cout << ans << '\n';
}