题意
给定正整数 \(n, k\),以及两个长为 \(n\) 的数列 \(\{q_n\}, \{r_n\}\)。若存在 \(x, y\in 1, k, y < x\) 使得 \(x = q_iy + r_j(i\neq j)\),则称其为一个匹配,求在保证每个 \(i\) 仅出现在一个匹配中的情况下最多有几组匹配。
思路
注意到 \(y\) 在 \(1, k\) 中任取,为了使 \(x\) 最小化,我们取 \(y = (r_j + 1)\)。所以:
\x = q_i(r_j + 1) + r_j (i\\neq j) \\
考虑贪心,先对 \(\{q_n\}, \{r_n\}\) 排序,让最小的 \(q_i\) 匹配最大的 \(r_j\),如果生成的 \(x\) 不满足小于等于 \(k\),则换一个更小的 \(r_j\),直到 \(q_i \geq k\) 或没有 \(r_j\) 可以再匹配,即可求出最大匹配个数。
那么这个做法为什么是对的呢?考虑从反面思考:如果 \(q_i\) 不去匹配最大(满足可行)的 \(r_j\),而是匹配小一些的 \(r_j'\),那么显然这组匹配是有冗余的。也就是说如果把 \(r_j'\) 让给一个更大的 \(q_i'\),有可能再促成一组匹配。所以对于每个 \(p_i\),它都应该匹配最大的可行的 \(r_j\)。
代码
代码如下。
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
int T, n;
ll k, q[N], r[N];
int main() {
scanf("%d", &T);
while (T--) {
int cnt = 0;
scanf("%d%lld", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &q[i]);
for (int i = 1; i <= n; i++)
scanf("%lld", &r[i]);
sort(q + 1, q + 1 + n), sort(r + 1, r + 1 + n);
int lo = 1, hi = n;
while (1) {
if (q[lo] >= k)
break;
// 如果此时的 q 值已经大于等于 k,那么没有必要继续匹配,一定不能成立
ll x = q[lo] * (r[hi] + 1) + r[hi];
bool f = false;
while (x > k) { // 如果此时 x > k,尝试换更小的 r
if (hi - 1 == 0) { // 此时已经没有 r 可以匹配,退出
f = true;
break;
}
hi--;
x = q[lo] * (r[hi] + 1) + r[hi];
}
if (x <= k) // 如果尝试之后匹配到了合适的 r
cnt++, lo++, hi--;
if (lo == n + 1 || hi == 0 || f) // 如果没有匹配到,退出
break;
}
printf("%d\n", cnt);
}
return 0;
}